vim script で遊ぶなら知っておきたい 10 の組み込み関数

vim script で遊ぶ時によく使う組み込み関数とか。
vimプラグインを作る場合だとまた違ってくると思います。
むしろ、そっちの方が誰かが書いてくれると嬉しいな(チラチラッ。
あと当然ながら詳細は help を参照してください。

☆まえがき

関数の可変長引数

関数の可変長引数は、リストで受け取ることが出来ます。

function! s:func(...)
    " a:0 は可変長引数の数
    echo a:0
    " a:000 可変長引数のリスト型
    echo a:000
endfunction

call s:func(42, 3.14, "hoge")
" 3
" [42, 3.14, 'hoge']
辞書型の関数定義

辞書には、関数も定義することが出来ます。

let s:dict = {}
let s:dict.value = 10
function! s:dict.func(value)
    " self で自分を参照する事ができる
    echo self.value + a:value
endfunction

" 関数の呼び出し
call s:dict.func(5)
" 15

☆type({expr})

{expr}の型を示す数値を返します。

数値 0
文字列 1
Funcref 2
リスト 3
辞書 4
浮動小数点数 5
let s:value = 10
echo type(0) == type(s:value)
" 1

☆eval({string})

文字列{string}を評価して、値を返します。

let s:value = 10
echo eval("s:value + 3")
" 13
echo eval("type(s:value) == type('')")
" 0

☆function({name})

関数{name}を参照する値を返します。

function! s:plus(a, b)
    return a:a + a:b
endfunction

" ユーザ定義関数
let s:func = function("s:plus")
echo s:func(4, 1)
" 5

" 組み込み関数
let s:func = function("type")
echo s:func(s:func) == type(s:func)
" 1

☆call({func}, {arglist} [, {dict}])

リスト{arglist} を引数として関数{func}を呼びます。

function! s:plus(a, b)
    return a:a + a:b
endfunction

" s:plus(3, 6) を呼ぶ
echo call("s:plus", [3, 6])
" 9

" function で定義した値を渡す事も可
let s:func = function("s:plus")
" s:plus(-6, 2)
echo call(s:func, [-6, 2])
" -4

" 辞書の関数を呼ぶ
let s:dict = {}
let s:dict.value = 9
function! s:dict.func(value)
    return self.value + a:value
endfunction

let s:func = s:dict.func
" 辞書の呼ぶ場合は、辞書も渡す必要がある
echo call(s:func, [4], s:dict)
" 13

☆keys({dict})/values({dict})

辞書{dict}のキー/値のリストを返します。

let s:dict = { "zero" : 0, "one" : 1, "two" : 2 }
echo values(s:dict)
" [1, 2, 0]

" for 文で使用する
for var in keys(s:dict)
    echo var
endfor
" one
" two
" zero

☆range({expr} [, {max} [, {stride}]])

連続した数値のリストを返します。

echo range(4)
" [0, 1, 2, 3]
echo range(2, 4)
" [2, 3, 4]
echo range(2, 9, 3)
" [2, 5, 8]
echo range(2, -2, -1)
" [2, 1, 0, -1, -2]
echo range(0)
" []
" echo range(2, 0)
" エラー

☆map({expr}, {string})

{expr}(リスト、辞書)の各要素を{string}で評価した結果で置き換えます。
{string}内では、v:val(要素の値)と v:key(辞書のキー)を使用することが出来ます。
{expr}は破壊的に変更されるので注意する必要があります。

let s:list = range(10)
call map(s:list, "v:val * v:val")
" s:list が直接変更される
echo s:list
" [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

" s:list を変更して欲しくない場合は、copy を使用する
let s:result = map(copy(s:list), "v:val + v:val")
echo s:result
" [0, 2, 8, 18, 32, 50, 72, 98, 128, 162]
echo s:list
" [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

☆filter({expr}, {string})

{expr}(リスト、辞書)の各要素に対して、{string}を評価し、その結果が 0 ならば削除します
map と同様に{string}内では、v:val(要素の値)と v:key(辞書のキー)を使用することが出来ます。
{expr}は破壊的に変更されるので注意する必要があります。

let s:list =range(10)
call filter(s:list, "v:val % 2 == 0")
echo s:list
" [0, 2, 4, 6, 8]

" s:list を変更して欲しくない場合は、copy を使用する
let s:result = filter(copy(s:list), "v:val > 4")
echo s:result
" [6, 8]
echo s:list
" [0, 2, 4, 6, 8]

☆join({list} [, {sep}])

リスト{list}の要素を連結し、文字列として返します。
{sep}が指定された時は、要素の間に{sep}を挿入します。

let s:list = range(10)
let s:result = join(s:list, ", ")
echo s:result
" 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

☆has_key({dict}, {key})

辞書{dict}が{key}の要素を持つなら1,持たないなら0を返します。

let s:dict = { "zero" : 0, "one" : 1, "two" : 2 }
echo has_key(dict, "zero")
" 1
echo has_key(dict, "three")
" 0

☆その他、応用

[FizzBuzz]

let s:fizzbuzz = 'v:val % 15 == 0 ? "FizzBuzz" : v:val % 3 == 0 ? "Fizz" : v:val % 5 == 0 ? "Buzz" : v:val'
echo map(range(1, 50), s:fizzbuzz)
" [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz', 13, 14, 'FizzBuzz', 16, 17, 'Fizz', 19, 'Buzz', 'Fizz', 22, 23, 'Fizz', 'Buzz', 26, 'Fizz', 28, 29, 'FizzBuzz', 31, 32, 'Fizz', 34, 'Buzz', 'Fizz', 37, 38, 'Fizz', 'Buzz', 41, 'Fizz', 43, 44, 'FizzBuzz', 46, 47, 'Fizz', 49, 'Buzz']

[foldl]

function! s:foldl(op, state, list)
    return eval(join(insert(a:list, a:state), a:op))
endfunction

echo s:foldl("+", 0, [1, 2, 3])
" 6
echo s:foldl("-", 0, [1, 2, 3])
" -6
echo s:foldl(".", "'list:'", [1, 2, 3])
" list:123

[apply]

function! s:apply(func, ...)
    return call(a:func, a:000)
endfunction

function! s:plus(...)
    return eval(join(copy(a:000), "+"))
endfunction

echo s:apply("s:plus", 3, 1, -5, 4)
" 3