2011年12月15日木曜日

Vimスクリプトの学習法 [Vim Advent Calendar 2011]【15日目】

この記事はVim Advent Calendar 2011の15日目の記事です.

Vimテクニックバイブルが出版され,様々な便利機能を知った人は多いと思います.しかし,これを自分で作れるか,作ろうと思い至れるか,と自問自答すると,作れない,思いつかない,という人もいると思います.

何故作れないのか,何故思いつけないのか,という疑問に対する自分なりの答えを2つほど考えてみました.
  1. Vimの機能を把握していない
  2. Vimスクリプトで問題を解くことに慣れていない
Vimの機能を知るほど,これってVimでやると楽なんだけどな,という作業が増えていきます.例えば,Vimのマクロ機能を知らない人は,100回同じ作業をしてしまうかもしれません.マクロ機能を知っている人は,これだけの作業をマクロにして,後は99回実行させれば良いな,と考えるでしょう.Vimの機能を知らないからこそ,Vimでやってみようという発想に至らないのだと思います.Vimの機能が把握できていないという問題は,Vimのドキュメントを読むことで解決できます.実際,一通り読んでいくと気づいていなかったり忘れていた機能に出会うことがあります.有志によるドキュメントの日本語訳も充実しているので,以前に比べてドキュメントを読むのは格段に楽になったと思います.

また,Vimスクリプトに用いる言語は少々癖があるので,慣れていないと上手く動かなくて途中で放り投げてしまったりするかもしれません.慣れるには何かを自分で作ってみたり,既存のスクリプトを弄ってみたりすれば良いのですが,特に作りたい物が無かったり,手頃な弄れそうなスクリプトが見つからない人もいるでしょう.そういう人にお勧めするのが,既存のプログラミング言語の問題集をVimスクリプトで解いてみる,ということです.
以下は,Higher-Order Perlの例題から,ハノイの塔をVimスクリプトに書き換えたものです.

let s:position = ['', 'A', 'A', 'A']

function! s:check_move(disk, start, end)
  let l:length = len(s:position) - 1
  if(a:disk < 1 || a:disk > l:length)
    echo "Bad disk number "  . a:disk . ". Should be 1.." . l:length . "."
  endif
  if(s:position[a:disk] != a:start)
    echo "Tried to move disk " . a:disk . " from " . a:start . 
          \ ", but it is on peg " . s:position[a:disk] . "."
  endif

  for i in range(0, a:disk - 1)
    if(s:position[i] == a:start)
      echo "Can't move disk " . a:disk . " from " . a:start .
            \ " because " . i . " is on top of it."
    elseif(s:position[i] == a:end)
      echo "Can't move disk " . a:disk . " to " . a:end .
            \ " because " . i . " is already there."
    endif
  endfor

  echo "Moving disk " . a:disk . " from " . a:start . " to " . a:end . "."
  let s:position[a:disk] = a:end
endfunction

function! s:hanoi(n, start, end, extra, move_disk)
  if a:n == 1
    call a:move_disk(1, a:start, a:end)
  else
    call s:hanoi(a:n - 1, a:start, a:extra, a:end, a:move_disk)
    call a:move_disk(a:n, a:start, a:end)
    call s:hanoi(a:n - 1, a:extra, a:end, a:start, a:move_disk)
  endif
endfunction

call s:hanoi(3, 'A', 'C', 'B', function('s:check_move'))

既存の問題集を利用する方法の利点は,どういう機能があればその問題が解けそうか,ということが分かっているため,ドキュメントを調べるのが楽だということです.

一流のVim使いというのは,Emacsを監視し,面白そうな機能があれば

「それVimでもできるよ」

と言うために移植を試みているようです.同じように,プログラミング言語も監視して

「それVimスクリプトでも書けるよ」

と言うために,各種プログラミング言語の問題集をVimスクリプトで書いてみることで,Vimスクリプトを学んでみてはいかがでしょうか? (実はこれを言いたかっただけという説もあったり無かったり)

以上

明日は,@yuzuemonさんです.

0 件のコメント:

コメントを投稿