Skip to content

Instantly share code, notes, and snippets.

@ongaeshi
Created February 9, 2017 06:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ongaeshi/910c8221b930c77cd64590a28230212b to your computer and use it in GitHub Desktop.
Save ongaeshi/910c8221b930c77cd64590a28230212b to your computer and use it in GitHub Desktop.
def _eval(exp, env)
if not list?(exp)
if immediate_val?(exp)
exp
else
lookup_var(exp, env)
end
else
if special_form?(exp)
eval_special_form(exp, env)
else
fun = _eval(car(exp), env)
args = eval_list(cdr(exp), env)
apply(fun, args)
end
end
end
def eval_special_form(exp, env)
if lambda?(exp)
eval_lambda(exp, env)
elsif let?(exp)
eval_let(exp, env)
end
end
def eval_list(exp, env)
exp.map{|e| _eval(e, env)}
end
def apply(fun, args)
if primitive_fun?(fun)
apply_primitive_fun(fun, args)
else
lambda_apply(fun, args)
end
end
def apply_primitive_fun(fun, args)
fun_val = fun[1]
fun_val.call(*args)
end
def lookup_var(var, env)
alist = env.find{|alist| alist.key?(var)}
if alist == nil
raise "couldn't find value to variables:'#{var}'"
end
alist[var]
end
def extend_env(parameters, args, env)
alist = parameters.zip(args)
h = Hash.new
alist.each { |k, v| h[k] = v }
[h] + env
end
def eval_let(exp, env)
parameters, args, body = let_to_parameters_args_body(exp)
new_exp = [[:lambda, parameters, body]] + args
_eval(new_exp, env)
end
def let_to_parameters_args_body(exp)
[exp[1].map{|e| e[0]},
exp[1].map{|e| e[1]},
exp[2]]
end
def eval_lambda(exp, env)
make_clousure(exp, env)
end
def make_clousure(exp, env)
parameters, body = exp[1], exp[2]
[:clousure, parameters, body, env]
end
def lambda_apply(closure, args)
parameters, body, env = closure_to_parameters_body_env(closure)
new_env = extend_env(parameters, args, env)
_eval(body, new_env)
end
def closure_to_parameters_body_env(closure)
[closure[1], closure[2], closure[3]] end
def list?(exp)
exp.is_a?(Array)
end
def lambda?(exp)
exp[0] == :lambda
end
def let?(exp)
exp[0] == :let
end
def primitive_fun?(exp)
exp[0] == :prim
end
def special_form?(exp)
lambda?(exp) or
let?(exp)
end
def immediate_val?(exp)
num?(exp)
end
def num?(exp)
exp.is_a? Numeric
end
def car(list)
list[0]
end
def cdr(list)
list[1..-1]
end
$primitive_fun_env = {
:+ => [:prim, lambda{|x,y| x + y }],
:- => [:prim, lambda{|x,y| x - y }],
:* => [:prim, lambda{|x,y| x * y }],
}
$global_env = [$primitive_fun_env]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment