ruby つくって学ぶプログラミング言语Ruby中的方案
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ruby つくって学ぶプログラミング言语Ruby中的方案相关的知识,希望对你有一定的参考价值。
# 式expを評価するときに環境envが追加された。
def _eval(exp, env)
# リストじゃなかったら
if not list?(exp)
# 数字の場合、そのまま返す。
if immediate_val?(exp)
exp
# 変数だった場合は、環境から値を取り出す。
else
lookup_var(exp, env)
end
else
# let式 λ式 の場合にマッチ
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 special_form?(exp)
lambda?(exp) or
let?(exp)
end
def lambda?(exp)
exp[0] == :lambda
end
def eval_special_form(exp, env)
if lambda?(exp)
# クロージャを作る。
eval_lambda(exp, env)
elsif let?(exp)
# let式 -> λ式へと変換してから式をexp評価。
eval_let(exp, env)
end
end
def eval_list(exp, env)
exp.map{|e| _eval(e, env)}
end
def list?(exp)
exp.is_a?(Array)
end
# プリミティブ関数を内包したハッシュ。
$primitive_fun_env = {
:+ => [:prim, lambda{|x, y| x + y}],
:- => [:prim, lambda{|x, y| x - y}],
:* => [:prim, lambda{|x, y| x * y}]
}
# リストの先頭
def car(list)
list[0]
end
# 先頭の次から最後の要素までのリスト
def cdr(list)
list[1..-1]
end
def immediate_val?(exp)
num?(exp)
end
def num?(exp)
exp.is_a?(Numeric)
end
def apply(fun, args)
if primitive_fun?(fun)
apply_primitive_fun(fun, args)
else
lambda_apply(fun, args)
end
end
def primitive_fun?(exp)
exp[0] == :prim
end
# プリミティブ関数に引数を適用する。
def apply_primitive_fun(fun, args)
# プリミティブ関数から式bodyを取り出す。
fun_val = fun[1]
# 配列を引数に渡すときは、可変長にする。
fun_val.call(*args)
end
# 環境env(ハッシュのリスト)から指定した変数の値を取り出す。
def lookup_var(var, env)
# envからシンボルに対応するハッシュを探す。[Hash], :var -> Hash?
var_hash = env.find{|vh| vh.key?(var)}
if var_hash == nil
raise "clodn't find value to variables:'#{var}'"
end
# Hash -> args
var_hash[var]
end
# シンボルと値のリストから作られたハッシュを環境envへ追加する。
def extend_env(parameters, args, env)
# シンボルと値の組のリスト
var_hash = parameters.zip(args)
# envへ追加するためにハッシュにする。
h = Hash.new
var_hash.each{|k,v| h[k] = v}
[h] + env
end
# let式をλ式へ変換してから評価する。
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
# シンボル:letを除いた式の本体を機械的に取り出す。
def let_to_parameters_args_body(exp)
[exp[1].map{|e| e[0]}, exp[1].map{|e| e[1]}, exp[2]]
end
def let?(exp)
exp[0] == :let
end
def eval_lambda(exp, env)
make_closure(exp, env)
end
# クロージャ(式 + 環境)を作る。
def make_closure(exp, env)
parameters, body = exp[1], exp[2]
[:closure, 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)
# 式本体bodyを新しい環境で評価。
_eval(body, new_env)
end
def closure_to_parameters_body_env(closure)
[closure[1], closure[2], closure[3]]
end
$global_env = [$primitive_fun_env]
#exp = [[:lambda, [:x, :y], [:+, :x, :y]], 3, 2]
exp = [:let, [[:x, 3]],
[:let, [[:fun, [:lambda, [:y], [:+, :x, :y]]]],
[:+, [:fun, 1], [:fun, 2]]]]
puts _eval(exp, $global_env)
以上是关于ruby つくって学ぶプログラミング言语Ruby中的方案的主要内容,如果未能解决你的问题,请参考以下文章
ruby つくって学ぶプログラミング言语Ruby中的方案
题解 AT25 プログラミングコンテスト
AtCoder全国統一プログラミング王決定戦予選/NIKKEI Programming Contest 2019
挑战程序设计竞赛 PDF下载
ruby PCからTHETAのシャッターを切る最小限のサンプルプログラム
ruby 自回答の転记Ref:[Ruby - Rubyで次の仕様を満たすPokemonクラスを持つプログラム...(98411)| teratail](https://teratail.com/q