tkykmw code

学びたいことを学ぶ

アンダースタンディング コンピュテーション 3章の感想とか

「単純なコンピュータから始めましょう」という導入で有限オートマトンが出てきて、しばらくはどういう展開につながるかわからないので、かなり面食らった。

3章全体が、最終的には「正規表現を作る」という形で、実用的な成果に至ることを押さえておけば、ぐっと読みやすくなるだろう。

そして久しぶりにプログラミング本の写経をして、悟ったことがある。

  1. ファイル監視ツールを使うべし
  2. ユニットテストを書くべし

1は先日ブログに書いた。

写経のお供にfilewatcher gemを使う

2について、結果が正しいか目視でチェックするなど、良きプログラマーはすべきでない。自動化すれば良いのだ。

特にこの本の場合、新たな概念の導入と並行して、段階的にコードを追加していくので、以前のコードがぶっ壊れてないか、不安すぎる。

また、あるオートマトンが何を意味するのか、遷移規則を見て判断するなど不可能だ。ユニットテスト(spec)に日本語変数名なども活用すれば、ぐっとわかりやすくなる。

context '自由移動を含むNFA' do
  let(:文字数が2または3の倍数のとき受理するrulebook) {
    NFA::Rulebook.new([
      FARule[1, nil, 2], FARule[1, nil, 4],
      FARule[2, 'a', 3], FARule[3, 'a', 2],
      FARule[4, 'a', 5], FARule[5, 'a', 6], FARule[6, 'a', 4]
    ])
  }
  let(:design) {
    NFA::Design.new(1, Set[2, 4], 文字数が2または3の倍数のとき受理するrulebook)
  }

  it '文字数が2の倍数のときは受理する' do
    expect(design.accepts?('aa')).to be_truthy
    expect(design.accepts?('aa' * 2)).to be_truthy
  end

  it '文字数が3の倍数のときは受理する' do
    expect(design.accepts?('aaa')).to be_truthy
    expect(design.accepts?('aaa' * 5)).to be_truthy
  end

  it '文字数が2の倍数でも3の倍数でもないときは受理しない' do
    expect(design.accepts?('aaaaa')).to be_falsy
    expect(design.accepts?('aaaaaaa')).to be_falsy
  end
end

なおコードを書きやすくするために、以下のような工夫をした。

  • alias :[] :new して FARule[…] みたいに短く書けるようにした
  • NFAとDFAを別モジュールに分けた