Vim script の lambda でクロージャ

Vim script の lambda ではローカル変数を変数をキャプチャできないので、function() で変数を束縛することで実装してみました。

[実装イメージ]

function! Counter()
    let value = 0
    function! Closure(local)
        let a:local.value += 1
        return a:local.value
    endfunction
    return function("Closure", [l:])
endfunction

let Count = Counter()

echo Count()
echo Count()
echo Count()
" => 1
" 2
" 3

[実装その1]

素直にそのまま lambda へと落としこんでみます。

let Counter = {
\   -> [
\       execute("let value = 0"),
\       function({
\           local -> [
\               execute("let local.value += 1"),
\               local.value
\           ][-1]
\       }, [l:])
\   ][-1]
\}

let Count = Counter()

echo Count()
echo Count()
echo Count()
" => 1
" 2
" 3

複数の式を評価するためにリストを利用しています。 それ以外は execute() を利用して変数の定義や代入を行っています。

[実装その2]

そもそもローカル変数の l: は辞書なので辞書で代用してみる。

let Counter = {
\   -> function({
\       local -> [
\           execute("let local.value += 1"),
\           local.value
\       ][-1]
\   }, [{"value" : 0}])
\}

let Count = Counter()

echo Count()
echo Count()
echo Count()
" => 1
" 2
" 3

ちょっとスッキリ。

[実装その3]

ここまで来たら辞書ではなくてもよいので、配列で代用。

let Counter = {
\   -> function({
\       value -> [
\           execute("let value[0] += 1"),
\           value[0]
\       ][-1]
\   }, [[0]])
\}

let Count = Counter()

echo Count()
echo Count()
echo Count()
" => 1
" 2
" 3

ここまで来るともはや面影がないですね。

[使用した vim のバージョン]

  • 7.4.2067