てきとう

てきとう

こんどこそTclでλ計算っぽいこと(まだ途中)

とりあえず、思いつきの方法で一つ前の問題を解決:

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"

*2


折角だからlambdaとcurryを使ってplusを書き直してみました。

set plus [lambda {x y} {expr $x+$y}]
set plus_2 [curry $plus 2]
{*}$plus_2 3

おお、綺麗綺麗。
lambdaとcurryを使う限り、最終的に実行する時だけ{*}は付ければいいようです。

*1:別に、URL載せておきながらここまで全く中身を読まなかったわけではありません。多分。

*2:「結果は」の「は」が化けて「<e3><81><af>」になってる…なんでかは分からない。