Curry

Prologで出来ることくらいCurryでも出来て欲しいよな〜というのは、まあ当然思うわけで、Prologのコード例を見ながら、Curryでは、どう書けばいいんだろうと暫く考えてみた。

日本語WikipediaPrologの項にあった、しょぼい例を適当に

data Name = John | Jack | Peter | Pochi | God deriving(Eq,Show)

isHuman(John) = True
isHuman(Jack) = True
isHuman(Peter) = True
isHuman(Pochi) = False
isHuman(God) = False

isDog x = case x of
 Pochi -> True
 otherwise -> False

mortal(x) = isHuman(x) || isDog(x)

main = print$findall(\x->mortal(x) =:= True)

は、きちんと正しい結果を返してくれる。それはいいんだけど、いくつか思うこととして、
・上のように型Nameを定義してしまうと、事前に、どういう名前があるか不明な時困る
・mortal(x) = isHuman(x) || isDog(x)という定義はいいんだけど、isHuman(x)=>mortal(x)、isDog(x)=>mortal(x)と気持ち的には分離して書きたい。


最初の点を克服しようと

data Name = Name String deriving(Show,Eq)

isHuman x = case x of
 Name "John" -> True
 Name "Jack" -> True
 Name "Peter" -> True
 otherwise -> False

main = print$findall(\x->isHuman(x) =:= True)

とかしても、suspendする


別の例。有向グラフの経路探索問題。ネタ元
http://bach.istc.kobe-u.ac.jp/prolog/intro/search.html

リンク先にある、以下のようなグラフを考える

             a1 
        v1 ──→ v2
        ↑        │
        │a4      │a2
        │        ↓
        v4 ←── v3 ──→ v5
             a3        a5

頂点uから頂点vへ到達する経路があるかどうか調べるという問題。

data Vertex = V1 | V2 | V3 | V4 | V5 deriving(Show,Eq)
data Arc = A1 | A2 | A3 | A4 | A5

arc(V1,V2) = A1
arc(V2,V3) = A2
arc(V3,V4) = A3
arc(V4,V1) = A4
arc(V3,V5) = A5

exists f = not$null(findall f)
walk u v = (u==v) || exists(\(e,w)->e=:=arc(u,w) & walk w v=:=True)

実行例。

main> walk V5 V3
False
main> walk V3 V2
True
main> walk V5 V2
False

正直、arcの定義は自然だとしても、walkの定義は、分かりやすいとは言えない気が。まあ、私がCurryのidiom(というものが形成されるほど使われてるのかも疑問だけど)を知らないせいで、もっといい書き方があるのかもしれないけど。それに、上の定義だと、findall(\x -> walk x V3 =:= True)とかはsuspendしてしまう。んでもって、最初の例と同様、上のコードは汎用性なし、特定のグラフに特化しすぎという問題。例えば、ファイルから、グラフの定義を読み込んで、そのグラフについて、到達可能性を求めたいとかいう場合、どうすればいいんだろう。template curryとかあればいいんだけどな〜。ていうか、そういうのPrologだとどう書くんだろう。Prologでも、
http://www.geocities.jp/m_hiroi/prolog/prolog01.html#chap4
とか見ると、類似の例はいくらでも発生しそうな気がしないでもないが。ただまあ、prologは動的型付けなので、何とかなるんだろう。ううん知らないけどきっとそう。というわけで、Narrowingがすげー便利な局面というのが全く思い浮かばないのだった。ていうか、いまいち挙動がよく分からないので、きちんとCurryのsemanticsを勉強してみよう

あと、not.nullが認識されない不具合。Zincコンパイラは、かなりbuggyな気がする。