とりあえず、思いつきの方法で一つ前の問題を解決:
set plus {x {format {y {expr %s+$y}} $x}} set plus_2 [apply $plus 2] puts [apply $plus_2 3] # 5
とか
set foo {bar {format {baz {apply {%s} $baz}} $bar}} apply [apply $foo {x {puts $x}}] hoge # hoge
とか
まぁ無理矢理なので当然というか、問題点が一杯です。
- format通すのは怠すぎる。
- applyが複数変数に対応してる意味って…。
と、ここまでかじったTclを数年ぶりに思い出した人間が頭の悪いやり方でやってきました。
しかし頭のいい人は世間にはいますので、ちゃんと綺麗にカリー化が出来るようなやり方を考えて下さっています。
最上部にも書いてあるhttp://www.tcl.tk/cgi-bin/tct/tip/194これですね。*1
そのページの中央付近にそのまんま書いてあります。
The availability of apply permits an easy and efficient access to other FP functions. For example one might define a constructor lambda and a curry command like this:
proc lambda {arglist body {ns {}}} { list ::apply [list $arglist $body $ns] } proc curry {lam args} { lappend lam {expand}$args }
抽象化する時にapplyも埋め込んでますね。
そのもう少し下の方に使い方も書いてあります。
set p [list ::apply [list x {string length $x}]] # or: set p [lambda x {string length $x}] {expand}$p $foo ;# or 'eval $p [list $foo]', or ...
原文ママですが、"{expand}"は"{*}"にしないと動きません。
"{*}"は文字列を展開します。
# "puts hoge" #"puts hoge"というコマンドが定義されていない限りこれはエラー {*}"puts hoge" #これはOK。結果は"hoge"
折角だからlambdaとcurryを使ってplusを書き直してみました。
set plus [lambda {x y} {expr $x+$y}] set plus_2 [curry $plus 2] {*}$plus_2 3
おお、綺麗綺麗。
lambdaとcurryを使う限り、最終的に実行する時だけ{*}は付ければいいようです。