SICP Chapter #1 Examples in Erlang -module(sicp01). -export([start/0]). print(X) -> io:write(X), io:format("~n"). start() -> section_1_1_1(), section_1_1_2(), section_1_1_3(), section_1_1_4(), section_1_1_5(), section_1_1_6(), section_1_1_7(), section_1_1_8(), section_1_2_1(), section_1_2_2(), section_1_2_3(), section_1_2_4(), section_1_2_5(), section_1_2_6(), section_1_3_1(), section_1_3_2(), section_1_3_3(), section_1_3_4(). % 1.1.1 The Elements of Programming - Expressions section_1_1_1() -> print (486), print (137 + 349), print (1000 - 334), print (5 * 99), print (10 div 5), print (2.7 + 10), print (21 + 35 + 12 + 7), print (25 * 4 * 12), print (3 * 5 + 10 - 6), print (3 * (2 * 4 + 3 + 5) + 10 - 7 + 6). % 1.1.2 The Elements of Programming - Naming and the Environment section_1_1_2() -> Size = 2, print (Size), 5 * Size, Pi = 3.14159, Radius = 10, print (Pi * Radius * Radius), Circumference = 2 * Pi * Radius, print (Circumference). % 1.1.3 The Elements of Programming - Evaluating Combinations section_1_1_3() -> print ((2 + 4 * 6) * (3 + 5 + 7)). % 1.1.4 The Elements of Programming - Compound Procedures section_1_1_4() -> print (square(21)), print (square(2 + 5)), print (square(square(3))), sum_of_squares(3, 4), print (f(5)). square(X) -> X * X. sum_of_squares(X, Y) -> square(X) + square(Y). f(A) -> sum_of_squares(A + 1, A * 2). % 1.1.5 The Elements of Programming - The Substitution Model for Procedure Application section_1_1_5() -> print (f(5)), print (sum_of_squares(5 + 1, 5 * 2)), print (square(6) + square(10)), print (6*6 + 10*10), print (36 + 100), print (f(5)), print (sum_of_squares(5 + 1, 5 * 2)), print (square(5 + 1) + square(5 * 2)), print (((5 + 1) * (5 + 1)) + ((5 * 2) * (5 * 2))), print ((6 * 6) + (10 * 10)), print (36 + 100), print (136). % 1.1.6 The Elements of Programming - Conditional Expressions and Predicates section_1_1_6() -> X = 6, print ((X > 5) andalso (X < 10)), % Exercise 1.1 print (10), print (5 + 3 + 4), print (9 - 1), print (6 div 2), print (2*4 + 4 - 6), A = 3, B = A + 1, print (A + B + A*B), print (A =:= B), print (if ((B > A) andalso (B < A * B)) -> B; true -> A end), print ( if (A =:= 4) -> 6; (B =:= 4) -> 6 + 7 + A; true -> 25 end), print (2 + (if (B > A) -> B; true -> A end)), print ( (if (A > B) -> A; (A < B) -> B; true -> -1 end) * (A + 1)), % Exercise 1.2 print ((5 + 4 + (2 - (3 - (6 + (4 / 5))))) / (3 * (6 - 2) * (2 - 7))). % Exercise 1.5 % commented out as this is in infinite loop % test(0, p()). abs_0(X) -> if (X > 0) -> X; true -> if (X =:= 0) -> 0; true -> -X end end. abs_1(X) -> if (X > 0) -> X; (X =:= 0) -> 0; true -> -X end. abs_2(X) -> if (X < 0) -> -X; true -> X end. abs_3(X) when (X < 0) -> -X; abs_3(X) -> X. ge(X, Y) -> (X > Y) orelse (X =:= Y). ge_1(X, Y) -> not(X < Y). % Exercise 1.3 three_n(N1, N2, N3) -> if (N1 > N2) -> if (N1 > N3) -> if (N2 > N3) -> N1*N1 + N2*N2; true -> N1*N1 + N3*N3 end; true -> N1*N1 + N3*N3 end; true -> if (N2 > N3) -> if (N1 > N3) -> N2*N2 + N1*N1; true -> N2*N2 + N3*N3 end; true -> N2*N2 + N3*N3 end end. % Exercise 1.4 a_plus_abs_b(A, B) -> if (B > 0) -> A + B; true -> A - B end. % Exercise 1.5 p() -> p(). test(X, Y) -> if (X =:= 0) -> 0; true -> Y end. % 1.1.7 The Elements of Programming - Example: Square Roots by Newton's Method section_1_1_7() -> print (sqrt(9)), print (sqrt(100 + 37)), print (sqrt(sqrt(2) + sqrt(3))), print (square(sqrt(1000))), % Exercise 1.6 print (new_if((2=:=3), 0, 5)), print (new_if((1=:=1), 0, 5)). good_enough(Guess, X) -> abs(square(Guess) - X) < 0.001. average(X, Y) -> (X + Y) / 2. improve(Guess, X) -> average(Guess, X / Guess). sqrt_iter(Guess, X) -> case good_enough(Guess, X) of true -> Guess; false -> sqrt_iter(improve(Guess, X), X) end. sqrt(X) -> sqrt_iter(1, X). % Exercise 1.6 new_if(Predicate, Then_Clause, Else_Clause) -> case (Predicate) of true -> Then_Clause; false -> Else_Clause end. sqrt_iter_0(Guess, X) -> new_if( good_enough(Guess, X), Guess, sqrt_iter(improve(Guess, X), X)). % from wadler paper newif_1(true, X, _) -> X; newif_1(false, _, Y) -> Y. % Exercise 1.7 good_enough_gp(Guess, Prev) -> (abs(Guess-Prev) / Guess) < 0.001. sqrt_iter_gp(Guess, Prev, X) -> case good_enough_gp(Guess, Prev) of true -> Guess; false -> sqrt_iter_gp(improve(Guess, X), Guess, X) end. sqrt_gp(X) -> sqrt_iter_gp(4, 1, X). % Exercise 1.8 improve_cube(Guess, X) -> (2*Guess + X/(Guess * Guess)) / 3. cube_iter(Guess, Prev, X) -> case good_enough_gp(Guess, Prev) of true -> Guess; false -> cube_iter(improve_cube(Guess, X), Guess, X) end. cube_root_0(X) -> cube_iter(27, 1, X). % 1.1.8 The Elements of Programming - Procedures as Black-Box Abstractions section_1_1_8() -> print (square(5)), print (sqrt_2(25)), print (sqrt_3(25)). % same as above % square(X) -> X * X. double(X) -> X + X. square_2(X) -> math:exp(double(math:log(X))). good_enough_1(Guess, X) -> abs(square(Guess) - X) < 0.001. improve_1(Guess, X) -> average(Guess, X / Guess). sqrt_iter_1(Guess, X) -> case (good_enough_1(Guess, X)) of true -> Guess; false -> sqrt_iter_1(improve_1(Guess, X), X) end. sqrt_1(X) -> sqrt_iter_1(1.0, X). % Block-structured sqrt_2(X) -> Good_Enough = fun (Guess, X) -> abs(square(Guess) - X) < 0.001 end, Improve = fun (Guess, X) -> average(Guess, X / Guess) end, Sqrt_Iter = fun (Self, Guess, X) -> case (Good_Enough(Guess, X)) of true -> Guess; false -> Self(Self, Improve(Guess, X), X) end end, Sqrt_Iter(Sqrt_Iter, 1.0, X). % Taking advantage of lexical scoping sqrt_3(X) -> Good_Enough = fun (Guess) -> abs(square(Guess) - X) < 0.001 end, Improve = fun (Guess) -> average(Guess, X / Guess) end, Sqrt_Iter = fun (Self, Guess) -> case (Good_Enough(Guess)) of true -> Guess; false -> Self(Self, Improve(Guess)) end end, Sqrt_Iter(Sqrt_Iter, 1.0). % 1.2.1 Procedures and the Processes They Generate - Linear Recursion and Iteration section_1_2_1() -> print (factorial(6)), print (factorial_0(6)), print (factorial_1(6)), print (a(1, 10)), print (a(2, 4)), print (a(3, 3)). % Recursive factorial(N) -> case (N =:= 1) of true -> 1; false -> N * factorial(N - 1) end. % alternate translation factorial_0(1) -> 1; factorial_0(N) -> N * factorial(N - 1). % Iterative fact_iter_1(Product, Counter, Max_Count) -> case (Counter > Max_Count) of true -> Product; false -> fact_iter_1(Counter * Product, Counter + 1, Max_Count) end. factorial_1(N) -> fact_iter_1(1, 1, N). % Iterative, block-structured (from footnote) factorial_2(N) -> Iter = fun (Self, Product, Counter) -> case (Counter > N) of true -> Product; false -> Self(Self, Counter * Product, Counter + 1) end end, Iter(Iter, 1, 1). % Exercise 1.9 inc(A) -> A + 1. dec(A) -> A - 1. plus(A, B) -> case (A =:= 0) of true -> B; false -> inc(plus(dec(A), B)) end. plus_1(A, B) -> case (A =:= 0) of true -> B; false -> plus(dec(A), inc(b)) end. % Exercise 1.10 a(_, 0) -> 0; a(0, Y) -> 2 * Y; a(_, 1) -> 2; a(X, Y) -> a(X - 1, a(X, Y - 1)). fx(N) -> a(0, N). g_1(N) -> a(1, N). h_1(N) -> a(2, N). k_1(N) -> 5 * N * N. % 1.2.2 Procedures and the Processes They Generate - Tree Recursion section_1_2_2() -> print (count_change(100)), print (fi(5)), print (fi_1(5)), print (pascals_triangle(5, 3)). % Recursive fib(0) -> 0; fib(1) -> 1; fib(N) -> fib(N - 1) + fib(N - 2). % Iterative fib_iter(_, B, 0) -> B; fib_iter(A, B, Count) -> fib_iter(A + B, A, Count - 1). fib_1(N) -> fib_iter(1, 0, N). % Counting change first_denomination(1) -> 1; first_denomination(2) -> 5; first_denomination(3) -> 10; first_denomination(4) -> 25; first_denomination(5) -> 50. cc(Amount, Kinds_Of_Coins) -> case (Amount =:= 0) of true -> 1; false -> case (Amount < 0) of true -> 0; false -> case (Kinds_Of_Coins =:= 0) of true -> 0; false -> cc(Amount, Kinds_Of_Coins - 1) + cc(Amount - first_denomination(Kinds_Of_Coins), Kinds_Of_Coins) end end end. count_change(Amount) -> cc(Amount, 5). % Exercise 1.11 fi(N) -> if (N < 3) -> N; true -> fi(N - 1) + 2 * fi(N - 2) + 3 * fi(N - 3) end. fi_iter(A, B, C, Count) -> if (Count =:= 0) -> C; true -> fi_iter(A + 2 * B + 3 * C, A, B, Count - 1) end. fi_1(N) -> fi_iter(2, 1, 0, N). % Exercise 1.12 pascals_triangle(N, K) -> if (N =:= 0) -> 1; (K =:= 0) -> 1; (N =:= K) -> 1; true -> pascals_triangle(N - 1, K - 1) + pascals_triangle(N - 1, K) end. % Alternate implementation using pattern matching pascals_triangle_2(0, _) -> 1; pascals_triangle_2(_, 0) -> 1; pascals_triangle_2(N, N) -> 1; pascals_triangle_2(N, K) -> pascals_triangle_2(N - 1, K - 1) + pascals_triangle_2(N - 1, N). % 1.2.3 Procedures and the Processes They Generate - Orders of Growth section_1_2_3() -> print (sine(60.0)). % Exercise 1.15 cube(X) -> X * X * X. px(X) -> (3.0 * X) - (4.0 * cube(X)). sine(Angle) -> case (abs(Angle) < 0.001) of true -> Angle; false -> px(sine(Angle / 3.0)) end. % 1.2.4 Procedures and the Processes They Generate - Exponentiation section_1_2_4() -> print (even(3)), print (multiply(3, 4)). % Linear recursion expt(_, 0) -> 1; expt(B, N) -> B * expt(B, (N - 1)). % Linear iteration expt_iter(_, 0, Product) -> Product; expt_iter(B, Counter, Product) -> expt_iter(B, Counter - 1, B * Product). expt_1(B, N) -> expt_iter(B, N, 1). % Logarithmic iteration even(N) -> ((N rem 2) =:= 0). fast_expt(_, 0) -> 1; fast_expt(B, N) -> case (even(N)) of true -> square(fast_expt(B, N div 2)); false -> B * fast_expt(B, N - 1) end. % Exercise 1.17 multiply(_, 0) -> 0; multiply(A, B) -> plus(A, multiply(A, dec(B))). % Exercise 1.19 fib_iter_2(_, B, _, _, 0) -> B; fib_iter_2(A, B, P, Q, Count) -> case (even(Count)) of true -> fib_iter_2(A, B, (P*P + Q*Q), (2*P*Q + Q*Q), Count div 2); false -> fib_iter_2((B * Q) + (A * Q) + (A * P), (B * P) + (A * Q), P, Q, Count - 1) end. fib_2(N) -> fib_iter_2(1, 0, 0, 1, N). % 1.2.5 Procedures and the Processes They Generate - Greatest Common Divisors section_1_2_5() -> print (gcd(40, 6)), % Exercise 1.20 print (gcd(206, 40)). gcd(A, 0) -> A; gcd(A, B) -> gcd(B, A rem B). % 1.2.6 Procedures and the Processes They Generate - Example: Testing for Primality section_1_2_6() -> timed_prime_test(13), % Exercise 1.21 print (smallest_divisor(199)), print (smallest_divisor(1999)), print (smallest_divisor(19999)), % Exercise 1.27 print (carmichael(561)), print (carmichael(1105)), print (carmichael(1729)), print (carmichael(2465)), print (carmichael(2821)), print (carmichael(6601)). % prime divides(A, B) -> ((B rem A) =:= 0). find_divisor(N, Test_Divisor) -> case (square(Test_Divisor) > N) of true -> N; false -> case (divides(Test_Divisor, N)) of true -> Test_Divisor; false -> find_divisor(N, Test_Divisor + 1) end end. smallest_divisor(N) -> find_divisor(N, 2). prime(N) -> (N =:= smallest_divisor(N)). % fast_prime expmod(_, 0, _) -> 1; expmod(Nbase, Nexp, M) -> case (even(Nexp)) of true -> square(expmod(Nbase, Nexp div 2, M)) rem M; false -> (Nbase * (expmod(Nbase, (Nexp - 1), M))) rem M end. fermat_test(N) -> Try = fun (A) -> (expmod(A, N, N) =:= A) end, Try(1 + random:uniform(N - 1)). fast_prime(_, 0) -> true; fast_prime(N, Ntimes) -> case (fermat_test(N)) of true -> fast_prime(N, Ntimes - 1); false -> false end. % Exercise 1.22 report_prime(Elapsed_Time) -> io:format(" *** ~w~n", [Elapsed_Time]). get_time() -> case (now()) of {_, Secs, _} -> Secs end. start_prime_test(N, Start_Time) -> case (prime(N)) of true -> report_prime(get_time() - Start_Time); false -> {} end. timed_prime_test(N) -> start_prime_test(N, get_time()). % Exercise 1.25 expmod_1(Nbase, Nexp, M) -> fast_expt(Nbase, Nexp) rem M. % Exercise 1.26 expmod_2(_, 0, _) -> 1; expmod_2(Nbase, Nexp, M) -> case (even(Nexp)) of true -> (expmod_2(Nbase, (Nexp div 2), M) * expmod_2(Nbase, (Nexp div 2), M)) rem M; false -> (Nbase * expmod_2(Nbase, Nexp - 1, M)) rem M end. % Exercise 1.27 carmichael(N) -> fast_prime(N, 100) andalso not(prime(N)). % 1.3 Formulating Abstractions with Higher-Order Procedures % same as above % cube(X) -> X * X * X. % 1.3.1 Formulating Abstractions with Higher-Order Procedures - Procedures as Arguments section_1_3_1() -> print (sum_cubes(1, 10)), print (sum_cubes_1(1, 10)), print (sum_integers(1, 10)), print (sum_integers_1(1, 10)), print (8.0 * pi_sum(1.0, 1000.0)), print (8.0 * pi_sum_1(1.0, 1000.0)), print (integral(fun cube/1, 0.0, 1.0, 0.01)), print (integral(fun cube/1, 0.0, 1.0, 0.001)), print(simpson(fun cube/1, 0.0, 1.0, 100)), print(sum_cubes_2(1, 10)), print(factorial_3(5)), print(factorial_4(5)), print(accumulate(fun plus/2, 0, fun identity/1, 1, fun inc/1, 5)), print(accumulate(fun multiply/2, 1, fun identity/1, 1, fun inc/1, 5)), print(accumulate_iter(fun plus/2, fun identity/1, 1, fun inc/1, 5, 0)), print(accumulate_iter(fun multiply/2, fun identity/1, 1, fun inc/1, 5, 1)), print(filtered_accumulate(fun plus/2, 0, fun square/1, 1, fun inc/1, 5, fun prime/1)). sum_integers(A, B) -> case (A > B) of true -> 0; false -> A + sum_integers(A + 1, B) end. sum_cubes (A, B) -> case (A > B) of true -> 0; false -> cube(A) + sum_cubes(A + 1, B) end. pi_sum(A, B) -> case (A > B) of true -> 0.0; false -> (1.0 / (A * (A + 2.0))) + pi_sum(A + 4.0, B) end. sum(Term, A, Next, B) -> case (A > B) of true -> 0; false -> Term(A) + sum(Term, Next(A), Next, B) end. % Using sum % same as above % inc(N) -> N + 1. sum_cubes_1(A, B) -> sum(fun (X) -> cube(X) end, A, fun inc/1, B). identity(X) -> X. sum_integers_1(A, B) -> sum(fun identity/1, A, fun inc/1, B). sum_float(Term, A, Next, B) -> case (A > B) of true -> 0.0; false -> Term(A) + sum_float(Term, Next(A), Next, B) end. pi_sum_1(A, B) -> Pi_Term = fun (X) -> 1 / (X * (X + 2)) end, Pi_Next = fun (X) -> X + 4.0 end, sum_float(Pi_Term, A, Pi_Next, B). integral(F, A, B, Dx) -> Add_Dx = fun (X) -> X + Dx end, sum_float(F, A + (Dx / 2), Add_Dx, B) * Dx. % Exercise 1.29 simpson(F, A, B, N) -> H = abs(B - A) / N, Sum_Iter = fun(Self, Term, Start, Next, Stop, Acc) -> if (Start > Stop) -> Acc; true -> Self(Self, Term, Next(Start), Next, Stop, Acc + Term(A + Start * H)) end end, H * Sum_Iter(Sum_Iter, F, 1, fun inc/1, N, 0.0). % Exercise 1.30 sum_iter(Term, A, Next, B, Acc) -> if (A > B) -> Acc; true -> sum_iter(Term, Next(A), Next, B, Acc + Term(A)) end. % 'sum_cubes_2' reimplements 'sum_cubes_' but uses 'sum_iter' in place of 'sum' sum_cubes_2(A, B) -> sum_iter(fun cube/1, A, fun inc/1, B, 0). % Exercise 1.31 % a. product(Term, A, Next, B) -> if (A > B) -> 1; true -> Term(A) * product(Term, Next(A), Next, B) end. factorial_3(N) -> product(fun identity/1, 1, fun inc/1, N). % b. product_iter(Term, A, Next, B, Acc) -> if (A > B) -> Acc; true -> product_iter(Term, Next(A), Next, B, Acc * Term(A)) end. factorial_4(N) -> product_iter(fun identity/1, 1, fun inc/1, N, 1). % Exercise 1.32 % a. accumulate(Combiner, NullValue, Term, A, Next, B) -> if (A > B) -> NullValue; true -> Combiner(Term(A), accumulate(Combiner, NullValue, Term, Next(A), Next, B)) end. % sum: accumulate(fun plus/2, 0, fun identity/1, A, fun inc/1, B). % product: accumulate(fun multiply/2, 1, fun identity/1, A, fun inc/1, B). % b. % NOTE: starting value of 'Acc' is 'NullValue' accumulate_iter(Combiner, Term, A, Next, B, Acc) -> if (A > B) -> Acc; true -> accumulate_iter(Combiner, Term, Next(A), Next, B, Combiner(Acc, Term(A))) end. % sum: accumulate_iter(fun plus/2, fun identity/1, A, fun inc/1, B, 0). % product: accumulate_iter(fun multiply/2, fun identity/1, A, fun inc/1, B, 1). % Exercise 1.33 filtered_accumulate(Combiner, NullValue, Term, A, Next, B, Pred) -> if (A > B) -> NullValue; true -> case Pred(A) of true -> Combiner(Term(A), filtered_accumulate(Combiner, NullValue, Term, Next(A), Next, B, Pred)); false -> filtered_accumulate(Combiner, NullValue, Term, Next(A), Next, B, Pred) end end. % a. % filtered_accumulate(fun plus/2, 0, fun square/1, 1, fun inc/1, 5, fun prime/1); % 39 % b. Not sure how to implement this without modifying 'filtered_accumulate' to have 'Pred' % accept two arguments % 1.3.2 Formulating Abstractions with Higher-Order Procedures - Constructing Procedures Using Lambda section_1_3_2() -> print (8.0 * pi_sum_2(1.0, 1000.0)), print (integral_1(fun (X) -> cube(X) end, 0.0, 1.0, 0.01)), Plus4 = fun (X) -> X + 4 end, print ((fun (X, Y, Z) -> X + Y + square(Z) end) (1, 2, 3)), % I need to figure out erlang's equivalent of let %X = 5, %let % val X = 3 %in % X + (X * 10) %end + X; %val X = 2; %let % val X = 3 % and Y = X + 2 %in % X * Y %end; % Exercise 1.34 print (f_5(fun (X) -> square(X) end)), print (f_5(fun (Z) -> Z * (Z + 1) end)). pi_sum_2(A, B) -> sum_float(fun (X) -> 1.0 / (X * (X + 2.0)) end, A, fun (X) -> X + 4.0 end, B). integral_1(F, A, B, Dx) -> sum_float(F, A + (Dx / 2), fun (X) -> X + Dx end, B) * Dx. plus4(X) -> X + 4. % Using let f_1(X, Y) -> F_Helper = fun (A, B) -> (X * square(A)) + (Y * B) + (A * B) end, F_Helper(1 + (X * Y), 1 - Y). f_2(X, Y) -> (fun (A, B) -> (X * square(A)) + (Y * B) + (A * B) end) (1 + (X * Y), 1 - Y). f_3(X, Y) -> A = 1 + (X * Y), B = 1 - Y, (X * square(A)) + (Y * B) + (A * B). f_4(X, Y) -> A = 1 + (X * Y), B = 1 - Y, (X * square(A)) + (Y * B) + (A * B). %% Exercise 1.34 f_5(G) -> G(2). % 1.3.3 Formulating Abstractions with Higher-Order Procedures - Procedures as General Methods section_1_3_3() -> print (half_interval_method(fun (X) -> math:sin(X) end, 2.0, 4.0)), print (half_interval_method(fun (X) -> (X * X * X) - (2.0 * X) - 3.0 end, 1.0, 2.0)), print (fixed_point(fun (X) -> math:cos(X) end, 1.0)), print (fixed_point(fun (Y) -> math:sin(Y) + math:cos(Y) end, 1.0)), print (sqrt_5(25)), print(golden_ratio()), print(fixed_point(fun(X) -> math:log(1000.0) / math:log(X) end, 1.5)), % Needs 'average_damp' from next section: % % average_damp(F) -> fun (X) -> average(X, F(X)) end. % print(fixed_point(average_damp(fun(X) -> math:log(1000.0) / math:log(X) end), 1.5)). % Half-interval method close_enough(X, Y) -> (abs(X - Y) < 0.001). positive(X) -> (X >= 0.0). negative(X) -> not(positive(X)). search(F, Neg_Point, Pos_Point) -> MidPoint = average(Neg_Point, Pos_Point), case (close_enough(Neg_Point, Pos_Point)) of true -> MidPoint; false -> Test_Value = F(MidPoint), case (positive(Test_Value)) of true -> search(F, Neg_Point, MidPoint); false -> case (negative(Test_Value)) of true -> search(F, MidPoint, Pos_Point); false -> MidPoint end end end. half_interval_method(F, A, B) -> A_Value = F(A), B_Value = F(B), case ((negative(A_Value)) andalso (positive(B_Value))) of true -> search(F, A, B); false -> case ((negative(B_Value)) andalso (positive(A_Value))) of true -> search(F, B, A); false -> {} %% raise Invalid("Values are not of opposite sign" ^ Real.toString(a) ^ " " ^ Real.toString(b)) end end. % Fixed points fixed_point(F, First_Guess) -> Tolerance = 0.00001, Close_Enough = fun (V1, V2) -> abs(V1 - V2) < Tolerance end, Try = fun (Self, Guess) -> Next = F(Guess), case (Close_Enough(Guess, Next)) of true -> Next; false -> Self(Self, Next) end end, Try(Try, First_Guess). % note: this function does not converge sqrt_4(X) -> fixed_point(fun (Y) -> X / Y end, 1.0). sqrt_5(X) -> fixed_point(fun (Y) -> average(Y, X / Y) end, 1.0). % Exercise 1.35 golden_ratio() -> fixed_point(fun (X) -> 1.0 + 1.0 / X end, 1.0). % Exercise 1.36 % Add the following line to function, 'fixed_point': % ... Next = F(Guess), % print(Next), % ... case ... % Exercise 1.37 % exercise left to reader to define cont_frac % cont_frac(fun (I) -> 1.0 end, fun (I) -> 1.0 end, K). % Exercise 1.38 - unfinished % Exercise 1.39 - unfinished % 1.3.4 Formulating Abstractions with Higher-Order Procedures - Procedures as Returned Values section_1_3_4() -> print ((average_damp(fun square/1)) (10.0)), print (sqrt_6(25)), print (cube_root(27)), print ((deriv(fun cube/1)) (5.0)), print (sqrt_7(25)), print (sqrt_8(25)), print (sqrt_9(25)), print(newtons_method(cubic(5.0, 3.0, 2.5), 1.0)), print((double_(fun inc/1))(5)), print((double_(double_(fun inc/1)))(5)), print((double_(double_(double_(fun inc/1))))(5)), print((compose(fun square/1, fun inc/1))(6)), print((repeated(fun square/1, 2))(5)), print(fixed_point(smooth(fun (X) -> math:log(1000.0) / math:log(X) end, 0.05), 1.5)), print(fixed_point_(average_damp(fun (X) -> math:log(1000.0) / math:log(X) end), 1.5)). average_damp(F) -> fun (X) -> average(X, F(X)) end. sqrt_6(X) -> fixed_point(average_damp(fun (Y) -> X / Y end), 1.0). cube_root(X) -> fixed_point(average_damp(fun (Y) -> X / square(Y) end), 1.0). % Newton's method deriv(G) -> Dx = 0.00001, fun (X) -> (G(X + Dx) - G(X)) / Dx end. % same as before % cube(X) -> X * X * X. newton_transform(G) -> fun (X) -> X - (G(X) / ((deriv(G))(X))) end. newtons_method(G, Guess) -> fixed_point(newton_transform(G), Guess). sqrt_7(X) -> newtons_method(fun (Y) -> square(Y) - X end, 1.0). % Fixed point of transformed function fixed_point_of_transform (G, Transform, Guess) -> fixed_point(Transform(G), Guess). sqrt_8(X) -> fixed_point_of_transform(fun (Y) -> X / Y end, fun average_damp/1, 1.0). sqrt_9(X) -> fixed_point_of_transform(fun (Y) -> square(Y) - X end, fun newton_transform/1, 1.0). % Exercise 1.40 cubic(A, B, C) -> fun (X) -> X*X*X + A*X*X + B*X + C end. % Exercise 1.41 double_(F) -> fun (X) -> F(F(X)) end. % Exercise 1.42 compose(F, G) -> fun (X) -> F(G(X)) end. % Exercise 1.43 repeated(F, N) -> Iterate = fun (Self, Arg, I) -> if (I > N) -> Arg; true -> Self(Self, F(Arg), I + 1) end end, fun (X) -> Iterate(Iterate, X, 1) end. % Exercise 1.44 ('n-fold-smooth' not implemented) smooth(F, Dx) -> fun (X) -> average(X, (F(X - Dx) + F(X) + F(X + Dx)) / 3.0) end. % Exercise 1.45 - unfinished % Exercise 1.46 ('sqrt' not implemented) iterative_improve(Good_enough, Improve) -> Iterate = fun (Self, Guess) -> Next = Improve(Guess), case Good_enough(Guess, Next) of true -> Next; false -> Self(Self, Next) end end, fun (X) -> Iterate(Iterate, X) end. fixed_point_(F, First_guess) -> Tolerance = 0.00001, Good_enough = fun (V1, V2) -> abs(V1 - V2) < Tolerance end, (iterative_improve(Good_enough, F))(First_guess). |