SICP Chapter #04 Examples in Erlang
-module(sicp04).
-import(scheme).
%-export([start/0]).
-compile(export_all).
print(X) ->
io:write(X),
io:format("~n").
start() ->
section_4_1_4(),
section_4_1_5(),
section_4_1_6().
% 4.1.1 - The Metacircular Evaluator - The Core of the Evaluator
section_4_1_1() ->
print ("").
eval({tm_unit}, Env) -> {val_unit};
eval({tm_bool, Exp}, Env) -> {val_bool, Exp};
eval({tm_int, Exp}, Env) -> {val_int, Exp};
eval({tm_real, Exp}, Env) -> {val_real, Exp};
eval({tm_string, Exp}, Env) -> {val_string, Exp};
eval({tm_quoted, Exp}, Env) -> {val_quoted, Exp};
eval({tm_if, Exp, E1, E2}, Env) -> case eval(Exp, Env) =:= {val_bool, true} of true -> eval(E1, Env); false -> eval(E2, Env) end;
eval({tm_cond, Exp}, Env) -> eval(cond2if(Exp), Env);
eval({tm_begin, Exp}, Env) -> lists:foldl(fun (X, _) -> eval(X, Env) end, {val_unit}, Exp);
eval({tm_symbol, Exp}, Env) -> lookup_variable_value(Exp, Env);
eval({tm_definition, E1, E2}, Env) -> define_variable(E1, eval(E2, Env), Env);
eval({tm_assignment, E1, E2}, Env) -> set_variable_value(E1, eval(E2, Env), Env);
eval({tm_lambda, Parms, Body}, Env) -> {val_closure, Parms, Body, Env};
eval({tm_application, F, Args}, Env) -> apply_(eval(F, Env), lists:map(fun (X) -> eval(X, Env) end, Args)).
apply_({val_primitive, Sym, F}, Args) -> F(Args);
apply_({val_closure, Parameters, Body, Env}, Args) ->
case length(Parameters) =/= length(Args) of
true ->
case length(Parameters) < length(Args) of
true -> throw({evaluator, "Too many arguments supplied"});
false -> throw({evaluator, "Too few arguments supplied"})
end;
false ->
% create the closure environment
NewEnv = [new_dictionary()|Env],
% pair up the parameters and arguments into a list
Pairs = list_pair_zip(Parameters, Args),
% push the parameters/arguments into the closure environment
lists:map(fun ({X, Y}) -> define_variable(X, Y, NewEnv) end, Pairs),
% evaluate the body of the closure
X = eval(Body, NewEnv),
% garbage collect the dictionary (note: this will kill tail-recursion)
ets:delete(hd(NewEnv)),
X
end;
apply_(F, Args) -> print(F), print(Args), throw ({evaluator, "Unknown procedure type -- APPLY"}).
% 4.1.3 - The Metacircular Evaluator - Evaluator Data Structures
new_dictionary() -> ets:new(frame, [ordered_set]).
lookup_variable_value(Var, [Frame|EnclosingEnvironment]) ->
case ets:member(Frame, Var) of
true ->
L = ets:lookup(Frame, Var),
case L of
[{Key, Val}] -> Val
end;
false -> lookup_variable_value(Var, EnclosingEnvironment)
end;
lookup_variable_value(Var, []) ->
print (Var),
throw ({evaluator, "Unbound variable ", Var}).
set_variable_value(Var, Val, [Frame|EnclosingEnvironment]) ->
case ets:contains(Frame, Var) of
true -> ets:insert(Frame, {Var, Val}), Val;
false -> set_variable_value(Var, Val, EnclosingEnvironment)
end;
set_variable_value(Var, Val, []) ->
throw ({evaluator, "Unbound variable -- SET! ", Var}).
define_variable(Var, Val, [Frame|_]) -> ets:insert(Frame, {Var, Val}), Val;
define_variable(Var, Val, []) -> throw ({evaluator, "Empty Environment ", Var}).
cond2if([{Pred, Exp}|Xs]) -> {tm_if, Pred, Exp, cond2if(Xs)};
cond2if([]) -> {tm_unit}.
list_pair_zip([H1|T1], [H2|T2]) -> [{H1, H2}|list_pair_zip(T1, T2)];
list_pair_zip([], []) -> [].
% 4.1.4 - The Metacircular Evaluator - Running the Evaluator as a Program
eval_print(TheGlobalEnvironment, Code) ->
Val = eval(Code, TheGlobalEnvironment),
print (Val),
Val.
section_4_1_4() ->
TheGlobalEnvironment = scheme:make_global_environment(),
eval_print(TheGlobalEnvironment, {tm_int, 123}),
% 1 + 6.
eval_print(TheGlobalEnvironment, {tm_application, {tm_symbol, '+'}, [{tm_int, 1}, {tm_int, 6}]}),
% 1 + (2 * 3).
eval_print(TheGlobalEnvironment,
{tm_application,
{tm_symbol, '+'},
[
{tm_int, 1},
{tm_application,{tm_symbol, '*'}, [{tm_int, 2}, {tm_int, 3}]}
]}),
% X = 6.
eval_print(TheGlobalEnvironment, {tm_definition, 'X', {tm_int, 6}}),
% (1 + X).
eval_print(TheGlobalEnvironment,
{tm_application,
{tm_symbol, '+'},
[
{tm_int, 1},
{tm_symbol, 'X'}
]}),
% Pi = 3.14.
eval_print(TheGlobalEnvironment, {tm_definition, 'Pi', {tm_real, 3.14}}),
% 27.0 / (13.0 - Pi).
eval_print(TheGlobalEnvironment,
{tm_application,
{tm_symbol, '/'},
[
{tm_real, 27.0},
{tm_application,
{tm_symbol, '-'},
[
{tm_real, 13.0},
{tm_symbol, 'Pi'}
]}
]}),
% square() -> fun (X) -> X * X end.
eval_print(TheGlobalEnvironment,
{tm_definition,
'square',
{tm_lambda,
['X'],
{tm_application,
{tm_symbol, '*'},
[
{tm_symbol, 'X'},
{tm_symbol, 'X'}
]}}}),
% Z = square(5.0).
eval_print(TheGlobalEnvironment,
{tm_definition,
'Z',
{tm_application,
{tm_symbol, 'square'},
[
{tm_real, 5.0}
]}}),
% append(Xs, Ys) ->
% case Xs =:= [] of
% true -> Ys;
% false -> [hd(Xs) | append(tl(Xs), Ys)
% end.
eval_print(TheGlobalEnvironment,
{tm_definition,
'append',
{tm_lambda,
['Xs', 'Ys'],
{tm_if,
{tm_application, {tm_symbol, '='}, [{tm_symbol, 'Xs'}, {tm_unit}]},
{tm_symbol, 'Ys'},
{tm_application,
{tm_symbol, 'cons'},
[
{tm_application, {tm_symbol, 'car'}, [{tm_symbol, 'Xs'}]},
{tm_application,
{tm_symbol, 'append'},
[
{tm_application, {tm_symbol, 'cdr'}, [{tm_symbol, 'Xs'}]},
{tm_symbol, 'Ys'}
]}
]}}}}),
% Xs = [a, b, c].
eval_print(TheGlobalEnvironment,
{tm_definition,
'Xs',
{tm_application,
{tm_symbol, 'cons'},
[
{tm_string, a},
{tm_application,
{tm_symbol, 'cons'},
[
{tm_string, b},
{tm_application, {tm_symbol, 'cons'}, [{tm_string, c}, {tm_unit}]}
]}
]}}),
% Ys = [d, e, f].
eval_print(TheGlobalEnvironment,
{tm_definition,
'Ys',
{tm_application,
{tm_symbol, 'cons'},
[
{tm_string, d},
{tm_application,
{tm_symbol, 'cons'},
[
{tm_string, e},
{tm_application, {tm_symbol, 'cons'}, [{tm_string, f}, {tm_unit}]}
]}
]}}),
% Zs = append(Xs, Ys).
eval_print(TheGlobalEnvironment, {tm_application, {tm_symbol, 'append'}, [{tm_symbol, 'Xs'}, {tm_symbol, 'Ys'}]}),
% if
% X > 0 -> X;
% X == 0 -> print('zero'), 0;
% true -> -X
% end.
eval_print(TheGlobalEnvironment,
{tm_cond,
[
{{tm_application, {tm_symbol, '>'}, [{tm_symbol, 'X'}, {tm_int, 0}]}, {tm_symbol, 'X'}},
{
{tm_application, {tm_symbol, '='}, [{tm_symbol, 'X'}, {tm_int, 0}]},
{tm_begin,
[
{tm_application, {tm_symbol, 'display'}, [{tm_string, "zero"}]},
{tm_int, 0}
]
}
},
{{tm_bool, true}, {tm_application, {tm_symbol, '-'}, [{tm_symbol, 'X'}]}}
]}),
% case X > 0 of
% true -> X;
% false ->
% case X =:= 0 of
% true -> print("zero"), 0;
% false -> -X
% end
% end.
eval_print(TheGlobalEnvironment,
{tm_if,
{tm_application, {tm_symbol, '>'}, [{tm_symbol, 'X'}, {tm_int, 0}]},
{tm_symbol, 'X'},
{tm_if,
{tm_application, {tm_symbol, '='}, [{tm_symbol, 'X'}, {tm_int, 0}]},
{tm_begin,
[
{tm_application, {tm_symbol, 'display'}, [{tm_string, "zero"}]},
{tm_int, 0}
]},
{tm_application, {tm_symbol, '-'}, [{tm_symbol, 'X'}]}}}),
% begin
% X = 3,
% Y = X + 2,
% Z = X + Y + 5,
% x * z
% end.
eval_print(TheGlobalEnvironment,
{tm_application,
{tm_lambda,
[],
{tm_begin,
[
{tm_definition, 'X', {tm_int, 3}},
{tm_definition, 'Y', {tm_application, {tm_symbol, '+'}, [{tm_symbol, 'X'}, {tm_int, 2}]}},
{tm_definition,
'Z',
{tm_application,
{tm_symbol, '+'},
[
{tm_symbol, 'X'},
{tm_application, {tm_symbol, '+'}, [{tm_symbol, 'Y'}, {tm_int, 5}]}
]}},
{tm_application, {tm_symbol, '*'}, [{tm_symbol, 'X'}, {tm_symbol, 'Z'}]}
]}},
[]}),
% The "and" is not working properly for val.
% The answer given is 5, but it should be 3.
% X = 1.
% begin
% X = 3
% Y = X + 2
% Y
% end.
eval_print(TheGlobalEnvironment, {tm_definition, 'X', {tm_int, 1}}),
eval_print(TheGlobalEnvironment,
{tm_application,
{tm_lambda,
[],
{tm_begin,
[
{tm_definition, 'X', {tm_int, 3}},
{tm_definition, 'Y', {tm_application, {tm_symbol, '+'}, [{tm_symbol, 'X'}, {tm_int, 2}]}},
{tm_symbol, 'Y'}
]}},
[]}),
% An extension to the eval function should address this problem:
% ((let? exp) (m-eval (let->combination exp) env))
% (define (let->combination let-exp)
% (let ((names (let-bound-variables let-exp))
% (values (let-values let-exp))
% (body (let-body let-exp)))
% (cons (list 'lambda names body) values)))
% fib(N) ->
% FibIter =
% fun (Self, A, B, Count) ->
% case Count of
% 0 -> B;
% true -> Self(Self, A+B, A, Count-1)
% end,
% FibIter(FibIter, 1, 0, N).
eval_print(TheGlobalEnvironment,
{tm_definition,
'fib',
{tm_lambda,
['N'],
{tm_begin,
[
{tm_definition,
'FibIter',
{tm_lambda,
['A', 'B', 'Count'],
{tm_if,
{tm_application, {tm_symbol, '='}, [{tm_symbol, 'Count'}, {tm_int, 0}]},
{tm_symbol, 'B'},
{tm_application,
{tm_symbol, 'FibIter'},
[
{tm_application, {tm_symbol, '+'}, [{tm_symbol, 'A'}, {tm_symbol, 'B'}]},
{tm_symbol, 'A'},
{tm_application, {tm_symbol, '-'}, [{tm_symbol, 'Count'}, {tm_int, 1}]}
]}}}},
{tm_application, {tm_symbol, 'FibIter'}, [{tm_int, 1}, {tm_int, 0}, {tm_symbol, 'N'}]}
]}}}),
% fib(10).
eval_print(TheGlobalEnvironment, {tm_application, {tm_symbol, 'fib'}, [{tm_int, 10}]}).
% 4.1.5 - The Metacircular Evaluator - Data as Programs
section_4_1_5() ->
TheGlobalEnvironment = scheme:make_global_environment(),
% factorial(N) ->
% case N =:= 1 of
% true -> 1;
% false -> N * factorial(N-1)
% end.
eval_print(TheGlobalEnvironment,
{tm_definition,
'factorial',
{tm_lambda,
['N'],
{tm_if,
{tm_application, {tm_symbol, '='}, [{tm_symbol, 'N'}, {tm_int, 1}]},
{tm_int, 1},
{tm_application,
{tm_symbol, '*'},
[
{tm_symbol, 'N'},
{tm_application,
{tm_symbol, 'factorial'},
[
{tm_application, {tm_symbol, '-'}, [{tm_symbol, 'N'}, {tm_int, 1}]}
]}
]}}}}),
% factorial(5}
eval_print(TheGlobalEnvironment, {tm_application, {tm_symbol, 'factorial'}, [{tm_int, 5}]}).
% Exercise 4.15
run_forever() -> run_forever().
halts(P, Q) -> true.
try_(P) ->
case halts(P, P) of
true -> run_forever();
false -> throw({halted})
end.
% 4.1.6 - The Metacircular Evaluator - Internal Definitions
section_4_1_6() ->
TheGlobalEnvironment = scheme:make_global_environment(),
% f(X) ->
% IsEven =
% fun (Self, IsOdd, 0) -> true;
% (Self, IsOdd, N) -> IsOdd(IsOdd, Self, N-1)
% end,
% IsOdd =
% fun (Self, IsEven, 0) -> false;
% (Self, IsEven, N) -> IsEven(IsEven, Self, N-1)
% end,
% ... rest of body of f ...,
% IsEven(IsEven, IsOdd, X).
eval_print(TheGlobalEnvironment,
{tm_definition,
'f',
{tm_lambda,
['X'],
{tm_begin,
[
{tm_definition,
'IsEven',
{tm_lambda,
['N'],
{tm_if,
{tm_application, {tm_symbol, '='}, [{tm_symbol, 'N'}, {tm_int, 0}]},
{tm_bool, true},
{tm_application,
{tm_symbol, 'IsOdd'},
[{tm_application, {tm_symbol, '-'}, [{tm_symbol, 'N'}, {tm_int, 1}]}]
}
}
}
},
{tm_definition,
'IsOdd',
{tm_lambda,
['N'],
{tm_if,
{tm_application, {tm_symbol, '='}, [{tm_symbol, 'N'}, {tm_int, 0}]},
{tm_bool, false},
{tm_application,
{tm_symbol, 'IsEven'},
[{tm_application, {tm_symbol, '-'}, [{tm_symbol, 'N'}, {tm_int, 1}]}]
}
}
}
},
{tm_application, {tm_symbol, 'IsEven'}, [{tm_symbol, 'X'}]}
]
}
}
}),
% f(3).
eval_print(TheGlobalEnvironment, {tm_application, {tm_symbol, 'f'}, [{tm_int, 3}]}),
% Exercise 4.19
% begin
% A = 1,
% F =
% fun (X) ->
% B = A + X,
% A = 5,
% A + B
% end,
% F(10)
% end.
eval_print(TheGlobalEnvironment,
{tm_begin,
[
{tm_definition, 'A', {tm_int, 1}},
{tm_definition,
'F',
{tm_lambda,
['X'],
{tm_begin,
[
{tm_definition, 'B', {tm_application, {tm_symbol, '+'}, [{tm_symbol, 'A'}, {tm_symbol, 'X'}]}},
{tm_definition, 'A', {tm_int, 5}},
{tm_application, {tm_symbol, '+'}, [{tm_symbol, 'A'}, {tm_symbol, 'B'}]}
]
}
}
},
{tm_application, {tm_symbol, 'F'}, [{tm_int, 10}]}
]
}),
% factorial(N) ->
% case N =:= 1 of
% true -> 1;
% false -> N * factorial(N-1)
% end.
eval_print(TheGlobalEnvironment,
{tm_definition,
'factorial',
{tm_lambda,
['N'],
{tm_if,
{tm_application, {tm_symbol, '='}, [{tm_symbol, 'N'}, {tm_int, 1}]},
{tm_int, 1},
{tm_application,
{tm_symbol, '*'},
[
{tm_symbol, 'N'},
{tm_application,
{tm_symbol, 'factorial'},
[
{tm_application, {tm_symbol, '-'}, [{tm_symbol, 'N'}, {tm_int, 1}]}
]}
]}}}}),
% Exercise 4.21
% Y Combinator
Y =
(fun (N) ->
fun (Fact) -> Fact(Fact(N)) end,
fun (Ft, 1) -> 1;
(Ft, K) -> K * Ft(Ft(K-1))
end
end)(10),
print (Y),
% _ = {EvalPrint
% tm_application(
% tm_application(
% tm_lambda(['Fact'] tm_application(tm_symbol('Fact') [tm_symbol('Fact')]))
% [
% tm_lambda(
% ['Ft']
% tm_lambda(
% ['K']
% tm_if(
% tm_application(tm_symbol('=') [tm_symbol('K') tm_int(1)])
% tm_int(1)
% tm_application(
% tm_symbol('*')
% [
% tm_symbol('K')
% tm_application(
% tm_application(tm_symbol('Ft') [tm_symbol('Ft')])
% [tm_application(tm_symbol('-') [tm_symbol('K') tm_int(1)])])
% ]))))
% ])
% [tm_int(10)])}
print ("").
y = fun (N) ->
fun (Fact) -> Fact(Fact(N)) end,
fun (Ft, 1) -> 1;
(Ft, K) -> K * Ft(Ft(K-1))
end
end,
|