About SICP The following Erlang code is derived from the examples provided in the book:
      "Structure and Interpretation of Computer Programs, Second Edition" by Harold Abelson and Gerald Jay Sussman with Julie Sussman.
      http://mitpress.mit.edu/sicp/

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,

Chris Rathman / Chris.Rathman@tx.rr.com