(is_numeric($expr)) { $val = (float) $expr; return [$val, $env]; } if ('true' === $expr) { return [true, $env]; } if ('false' === $expr) { return [false, $env]; } if ('null' === $expr) { return [null, $env]; } $var = $expr; return [$env[$var], $env]; } $fn = array_shift($expr); $args = $expr; if ('define' === $fn) { list($var, $val) = $args; list($val, $env) = evaluate($val, $env); $env = array_merge($env, [$var => $val]); return [null, $env]; } if ('lambda' === $fn) { list($lambda_args, $code) = $args; $closure = ['closure', $lambda_args, $code, $env]; return [$closure, $env]; } if ('if' === $fn) { list($cond, $then, $else) = $args; $cond = evaluate($cond, $env)[0]; if ($cond === true) { $val = evaluate($then, $env)[0]; } else { $val = evaluate($else, $env)[0]; } return [$val, $env]; } ! $fn = evaluate($fn, $env)[0]; $args = array_map(function ($arg) use ($env) { return evaluate($arg, $env)[0]; }, $args); return apply($fn, $args, $env); } ! function apply($fn, $args, $env) { list($_, $lambda_args, $code, $closure_env) = $fn; ! $env = array_merge($env, $closure_env); $env = array_merge($env, array_combine($lambda_args, $args)); return evaluate_code($code, $env); } function evaluate_code($code, $env = []) { foreach ($code as $expr) { list($val, $env) = evaluate($expr, $env); } return [$val, $env]; }