Rubyでcall by nameっぽいこと
Algol60の引数機構であるcall by nameは今ではすっかり廃れて若い人には知られていないと思われるが、一言で言うと「クロージャを引数に渡す」ということで、クロージャの表記が非常にコンパクト。変数や式がそのままクロージャになる。
Algol60のサンプルプログラム*1:
VALUE指定のfromとtoがcall by valueで、それ以外のsumとvarとexprの引数がcall by name。
BEGIN INTEGER m,n; PROCEDURE sub(sum, var, expr, from, to); VALUE from, to; INTEGER sum, var, expr, from, to; BEGIN sum := 0; FOR var := from STEP 1 UNTIL to DO sum := sum + expr; END; sub(m, n, n*n, 1, 10); print(m); END
少し解説すると、subでsumに代入すると実引数であるmへの代入となる。varへの代入も同じくnへの代入となる。これだけならcall by referenceでも同じだ。違うのは、exprを評価すると、その時点で呼び出し側環境でn*nを評価してその結果を値とする。つまりn*nがクロージャとしてsubにexprという名前で渡ったことになる。
対応するRubyプログラム:
call by name の代わりに、値をセットするクロージャと値をゲットするクロージャのペアを渡す。式に対しての値のセットはエラーにする。
def sub(setsum,getsum,setvar,getvar,setexpr,getexpr,from,to) setsum[0] for i in from..to setvar[i] setsum[ getsum[] + getexpr[] ] end end m=nil n=nil sub( lambda{|x| m=x}, lambda{m}, lambda{|x| n=x}, lambda{n}, lambda{raise "bad use"}, lambda{ n*n }, 1, 10 ) puts m
うーん、これは手で書く気がしない。