“lethevert is a programmer - 言語を選ぶ基準”を Smalltalk で
一般的な Smalltalk の場合、
| f | f := [:x | | g h | g := [:y | x + y]. h := [:x | g value: 10]. h]. (f value: 10) value: 1 "=> 20 "
残念ながら、Squeak Smalltalk ではこれでは駄目で、h のブロック変数名に x (すでに f のブロック変数として宣言されている…)は使えません。
| f | f := [:x | | g h | g := [:y | x + y]. h := [:x1 | g value: 10]. h]. (f value: 10) value: 1 "=> 20 "
Ruby に直訳すると、こんなかんじ。
f = proc do |x| g = proc { |y| x + y } h = proc { |x1| g.call(10) } h end f.call(10).call(1)
また、Ruby で f のみメソッドにする版を、むりやり Squeak Smalltalk にて意訳すると…
self class compile: 'f: x | g h | g := [:y | x + y]. h := [:x1 | g value: 10]. ^h'. (self f: 10) value: 1 "=> 20 "
さらに悪のりして、ブロックを使わず、メソッドのみで同じことを実現する版も。(^_^;)
self class compile: 'f: x self class compile: ''g: y ^x + y''. (self class >> #g: literalAt: 1) value: x. self class compile: ''h: x ^self g: 10''. ^self class >> #h:'. (self f: 10) valueWithReceiver: self arguments: 1 "=> 20 "
self class が邪魔だなーと思いつつよく考えたら、これらのメソッドを起動するためのメッセージのレシーバは、self(トップレベルではたいていは nil …)である必要はないんですよね。Smalltalk のメッセージ式においては、通常の言語の第一オペランドや第一引数がレシーバに相当することを考慮すれば、各メソッドのパラメータ変数である x、y は、たとえば、Smalltalk では階乗を 10 factorial と書くようにレシーバ(それぞれのメソッド実行中のコンテキストでの self )として置き換え可能なので、もうすこしシンプル(?)にできそうです。
Integer compile: 'f Integer compile: ''g ^x + self''. (Integer >> #g literalAt: 1) value: self. Integer compile: ''h ^10 g''. ^Integer >> #h'. 10 f valueWithReceiver: 1 arguments: #()
#f が返してくる #h の起動も短く書けないかと、せっかく #h にアサインしているのでこれを活用し、定義したメソッド #h のオブジェクト本体の代わりにシンボル #h を返させて、
Integer compile: 'f Integer compile: ''g ^x + self''. (Integer >> #g literalAt: 1) value: self. Integer compile: ''h ^10 g''. ^#h'. 10 f value: 1
短くはなりますが、意味不明さは相変わらず。w むしろ BlockContext >> #value: と混同してさらに悪いことになっているかも。ちなみにここで使っている Symbol >> #value: の定義は、Squeak3.9 では、こんなふう。
Symbol >> value: obj
^obj perform: self