PrologとHaskellの挙動の違い
foo(0)とfoo(N)を用意しておいて、Nの時にはなにか処理をしてからfoo(N - 1)を再帰呼び出しする、というコーディングパターンをPrologで使う際に、Haskellの発想で書くと罠にハマるのでメモ。
まずHaskellで挙動を確認してみる。
foo 0 = do{ print "rule1"; print 0 } foo n = do{ print "rule2"; print n } main = do foo (1 - 1) foo 1 foo 0
"rule1" 0 "rule2" 1 "rule1" 0
foo(1 - 1)でfoo 0の定義が呼ばれていることがわかる。またfoo 0でfoo 0の定義だけが呼ばれていることがわかる。(何を当たり前のことを、と思うかもしれないけども、その思い込みにハマった)
Prologで同じような書き方をしてみよう。
foo(0) :- print('rule1: '), print(0). foo(N) :- print('rule2: '), print(N).
?- foo(1 - 1). rule2: 1-1 true. ?- foo(1). rule2: 1 true. ?- foo(0). rule1: 0 true ; rule2: 0 true.
Prologでは、まずfoo(1 - 1)はfoo(0)にマッチしないのでrule2になっている。Haskellではパターンマッチのタイミングで1-1の評価が強制されて0になるが、Prologではされない。またfoo(0)の時に、rule1にマッチした後、rule2にもマッチしている。
Prologでフィボナッチを計算している例などを見ると、うまくこの落とし穴を避けるような書き方をしてある。出かけないといけないので続きはまた今度。ヒントはカットとis。