VimScript その後
最終的にこんな感じになりました。
本当に誰得……。
[使い方]
" 実装部は下記参照 function! s:minus(a, b) return a:a - a:b endfunction " s:apply で関数を評価する echo s:apply("s:minus", 5, 2) " 3 let joint = {} function! joint.apply(a, b) return a:a.a:b endfunction " 辞書が apply 関数を持っていれば、それを評価する echo s:apply(joint, "hoge", "foo") " hogefoo " 無名関数を作成 " a:1 と a:2 は引数の順番 let plus = s:lambda("a:1 + a:2") " s:apply で評価 echo s:apply(plus, 2, 5) " 7 " s:bind で、部分適用出来る " _1 は、第一引数が渡される let twice = s:bind(plus, _1, _1) " こっちも s:apply で評価 echo s:apply(twice, 10) echo s:apply(twice, [1, 2], [3, 4]) " 20 " [1, 2, 1, 2] " こんな使い方も let equal_type = s:lambda("type(a:1) == type(a:2)") echo s:apply(equal_type, 10, 4) echo s:apply(equal_type, [1, 2, 3], {"one": 1, "two" : 2, "three" : 3}) " 1 " 0 " がんばれば再帰も出来る " 自分を評価するには self を使用する let fact = s:lambda("(a:1 == 1) ? 1 : s:apply(self, a:1-1) * a:1") echo s:apply(fact, 4) " 24 let sum = s:lambda("(len(a:1) == 1) ? a:1[0] : s:apply(self, a:1[1:-1]) + a:1[0]") echo s:apply(sum, range(1, 10)) " 55 " ちょっと複雑ですがこんな事も…!! function! s:var(var) let func = { "var" : a:var } function! func.apply(...) dict return self.var endfunction retur func endfunction function! s:if(pred, then, else) let func = { \ "pred" : a:pred, \ "then" : a:then, \ "else" : a:else \} function! func.apply(...) dict if s:apply_args_list(self.pred, a:000) return s:apply_args_list(self.then, a:000) else return s:apply_args_list(self.else, a:000) endif endfunction return func endfunction let is_dict = s:bind(equal_type, _1, {}) let get_dict = s:if(is_dict, _1, s:var("nothing")) echo s:apply(get_dict, {"dict" : 10}) echo s:apply(get_dict, "hoge") " {'dict': 10} " nothing
[出力]
3 hogefoo 7 20 [1, 2, 1, 2] 1 0 24 55 {'dict': 10} nothing
まぁ概ねやりたかったことは出来たかな。
組み込み関数の call と eval が強力ですね……。
動的言語は書くのが楽です。
しかし、再帰とかマジ誰得。
さて、切りがいいので、そろそろ github 辺りにまとめたい所。
次は、range 回りの処理を書く予定。
上記のソースの実装は以下から
function! s:apply(func,...) if type(a:func) == type({}) && has_key(a:func, "apply") return call(a:func.apply, a:000, a:func) elseif(type(a:func) == type(function("function"))) return call(a:func, a:000) else return call(function(a:func), a:000) endif endfunction function! s:apply_args_list(func, args) return call("s:apply", [a:func] + a:args) endfunction function! s:dict_func(func) let dict = { "func" : a:func } function! dict.apply(...) dict return call(self.func, a:000[1:-1], a:1) endfunction return dict endfunction function! s:placeholders(args_no) let func = {"args_no" : a:args_no} function! func.apply(...) dict return a:000[self.args_no] endfunction return func endfunction let _1 = s:placeholders(0) let _2 = s:placeholders(1) let _3 = s:placeholders(2) function! s:bind(func, ...) let func = {"func" : a:func, "args" : a:000} function! func.apply(...) dict let args=[] for var in self.args if type(var) == type({}) && has_key(var, "apply") call add(args, call(var.apply, a:000, var)) else call add(args, var) endif unlet var endfor return s:apply_args_list(self.func, args) endfunction return func endfunction function! s:lambda(lambda) let func = { "lambda" : a:lambda } function! func.apply(...) dict return eval(self.lambda) endfunction return func endfunction function! s:minus(a, b) return a:a - a:b endfunction " s:apply で関数を評価する echo s:apply("s:minus", 5, 2) let joint = {} function! joint.apply(a, b) return a:a.a:b endfunction " 辞書が apply 関数を持っていれば、それを評価する echo s:apply(joint, "hoge", "foo") " 無名関数を作成 " a:1 と a:2 は引数の順番 let plus = s:lambda("a:1 + a:2") " s:apply で評価 echo s:apply(plus, 2, 5) " s:bind で、部分適用出来る " _1 は、第一引数が渡される let twice = s:bind(plus, _1, _1) " こっちも s:apply で評価 echo s:apply(twice, 10) echo s:apply(twice, [1, 2], [3, 4]) " こんな使い方も let equal_type = s:lambda("type(a:1) == type(a:2)") echo s:apply(equal_type, 10, 4) echo s:apply(equal_type, [1, 2, 3], {"one": 1, "two" : 2, "three" : 3}) " がんばれば再帰も出来る " 自分を評価するには self を使用する let fact = s:lambda("(a:1 == 1) ? 1 : s:apply(self, a:1-1) * a:1") echo s:apply(fact, 4) let sum = s:lambda("(len(a:1) == 1) ? a:1[0] : s:apply(self, a:1[1:-1]) + a:1[0]") echo s:apply(sum, range(1, 10)) " ちょっと複雑ですがこんな事も…!! function! s:var(var) let func = { "var" : a:var } function! func.apply(...) dict return self.var endfunction retur func endfunction function! s:if(pred, then, else) let func = { \ "pred" : a:pred, \ "then" : a:then, \ "else" : a:else \} function! func.apply(...) dict if s:apply_args_list(self.pred, a:000) return s:apply_args_list(self.then, a:000) else return s:apply_args_list(self.else, a:000) endif endfunction return func endfunction let is_dict = s:bind(equal_type, _1, {}) let get_dict = s:if(is_dict, _1, s:var("nothing")) echo s:apply(get_dict, {"dict" : 10}) echo s:apply(get_dict, "hoge")