functions and procedures. To SICP´s point of view the
contrast between functions and procedures is a reflection of
the general distinction between describing properties of things
and describing how to do things, or the distinction between
declarative knowledge and imperative knowledge.
As a programming example to work on, introduces procedures
as an effective way to describe programatically mathematical functions.
The problem selected is "Square roots by Newton's method".
Scheme's implementation define a main body that checks if the
parameters are good enough (auxiliary funtion) if so recurses using
calculated result of "improve" , a second auxiliary parametrized function.
I will start my implementation of exercise 1.1.7 writing F#'s version
of this small set of auxiliary function: average , good-enough?
and improve. After due test of this set, i will implement the main body
of the procedure, last step would be integrate all in one parametrized
sqrt procedure with one parameter x.
So , let's start with the simplest auxiliary functions.Implement average
is quite straightforward , just two algebraic operation, a sum and then
division.
let average x y =
( x + y) / 2
//test on interactive
let testAv = average 2 3
val testAv : int = 2
this test return 2 , I was especting 2.5 ¿What is the deal?
Retrying with float valued parameters gives the following
error:
Evaluating testAv2 on REPL gives an error FS0001:
This expression was exepcted to have type in but here
has type float
So, it look like the type inferencer decided int to be expectedThis expression was exepcted to have type in but here
has type float
type of x y, inference resolved by the parameters of my test
and the type of the divisor.In order to work with floats,
enter "type annotations".This annotation is a way to restrict an
argument type.In this case I should select
float as x & y's type .Also division by integer 2 is replaced by
division by 2.0.
let average ( x : float) (y : float ) =
( x + y) / 2.0
//Test it
let testAv2 = average 2.0 3.0
//Results:
val testAv2 : float = 2.5
let good_enough (guess : float) (x : float) =
let square x = x * x
abs (square guess - x) < 0.01
Advice:don't use interrogation sign as last
Due test on the interactive compiler:
//Test
let testGood = good_enough 1.0 1.5
//Results:
val testGood : bool = false
The last of our set of auxiliary functions improvesval testGood : bool = false
the guess using average function:
let improve (guess : float ) ( x : float) =
let average ( x : float) (y : float ) =
( x + y) / 2.0
average guess (x / guess)
//Test:
let testImp = improve 1.0 1.5
//Results:
val improve : float -> float -> float
Sqrt_iter has the role of main function
wifh will call the auxiliary ones.
let rec sqrt_iter ( guess : float ) ( x : float ) =
if (good_enough guess x) thenguess
else sqrt_iter ( improve guess x) x
//As test , trying to get the square root of 2:
let testSqrt = sqrt_iter 1.0 2.0
//Results:/
val tesSqrt : float = 1.416666667
Finally, I will refactor all previous snippets
in order to have a well formed , block structured
program:
let rec sqrt_iter ( guess : float ) ( x : float ) =
let good_enough (guess : float) (x : float) =
let square x = x * x
abs (square guess - x) < 0.01
let improve (guess : float ) ( x : float) =
let average ( x : float) (y : float ) =
( x + y) / 2.0
average guess (x / guess)
if (good_enough guess x) then
guess
else sqrt_iter ( improve guess x) x
let sqrt x =
sqrt_iter 1.0 x