Vimのプラグインを書いていてcurryingを使いたい場合が出てきたので、どうすれば実現できるかちょっとだけ考えてみました。
function! Curry(f, x)
let d = {}
let d.f = a:f
let d.x = a:x
function! d.__call__(...)
return call(self.f, [self.x] + a:000)
endfunction
return d
endfunctionfunction! Apply(func, args)
if type(a:func) == type({})
if has_key(a:func, '__call__')
return call(a:func.__call__, a:args, a:func)
else
throw 'This dictionary is not callable:' string(a:func)
endif
else
return call(a:func, a:args)
endif
endfunctionfunction! Sub(x, y)
return a:x - a:y
endfunction
let sub3 = Curry(function('Sub'), 3)
echo Apply(sub3, [4002]) " ==> 3339難点は普通の関数と同様の形式で呼び出せないこと。Curryingされた関数(例ではsub3)を呼び出す場合、本来の関数(Sub)と事前に渡されていた引数(3)を何らかの方法でメモしておかなければなりません。このメモを行うこと自体はDictionary-functionを使えば簡単にできます。しかしDictionary-functionの呼び出しは用いるべきDictionaryを明示的に渡す必要があるため、通常の関数と同様の形式で呼び出すことができません(どうしてもdict.func(...)またはcall(func, args, dict)の形式になる)。
上記の実装ではApply()を使って誤魔化してますが、何だかなぁ、と言う感じ。
余談: Vim scriptではスコープの接頭辞のみの式(s:やg:)でスコープに属する変数を管理するDictionaryが得られます。これを利用すればclosureもどきができそうな気がしたのですが、lexical scopeもどきの実現が面倒臭過ぎるので放棄気味。関数実行時のローカルスコープl:は実行終了と同時に破棄されることが面倒さに拍車をかけています。下手に扱うとVimがクラッシュします。というか今日は1回それでクラッシュして半泣きしました。