Curry
Prologで出来ることくらいCurryでも出来て欲しいよな〜というのは、まあ当然思うわけで、Prologのコード例を見ながら、Curryでは、どう書けばいいんだろうと暫く考えてみた。
日本語WikipediaのPrologの項にあった、しょぼい例を適当に
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な気がする。