なにやらClojureで論理プログラミングをするためのものらしいのでいろいろと試してみた。
よく例に出るappendの例。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(use 'clojure.core.logic) | |
(defne append [x y z] | |
([() a a]) | |
([[a . b] _ [a . c]] | |
(append b y c))) |
xとyが連結するリスト、zが連結後のリストです。
xが空ならyとzは同じ。
xの先頭とzの先頭が同じなら、xのテールとyを連結したzのテールになる。
普通の関数で書いたらこんな感じ?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(use '[clojure.core.match :only [match]]) | |
(defn append [x y] | |
(match [x] | |
[[]] y | |
[[h & t]] (recur t (cons h y)))) |
しかし、普通の関数と違ってかなり高機能です。
実行してみます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(assert (= (run* [q] (append [1 2] [3 4] q)) | |
'((1 2 3 4)))) | |
(assert (= (run* [q] (append [1 2] q [1 2 3 4])) | |
'((3 4)))) | |
(assert (= (run* [q] (fresh [a b] | |
(== q [a b]) | |
(append a b [1 2 3 4]))) | |
'([() (1 2 3 4)] [(1) (2 3 4)] [(1 2) (3 4)] [(1 2 3) (4)] [(1 2 3 4) ()]))) |
なんと、append一つ定義するだけで連結・差分・組み合わせの三つの使い方が出来るのです!
おー、論理プログラミングすげー
さらに、ClojureScript版も用意されています。
上記のappendのコードは動きますが、clojure.core.logicと比べると定義されている関数やマクロは少ないです。
バグってたりします。
数独も解いてみた。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(use 'clojure.core.logic) | |
(def _1 [()]) | |
(def _2 [() ()]) | |
(def _3 [() () ()]) | |
(def _4 [() () () ()]) | |
(defne different [list] | |
([()]) | |
([[x . ()]]) | |
([[x . [h . t]]] | |
(fresh [l] | |
(!= x h) | |
(conso x t l) | |
(different l)))) | |
(defne lte [m n] | |
([() _]) | |
([[_ . x] [_ . y]] | |
(lte x y))) | |
(defne gte [m n] | |
([_ ()]) | |
([[_ . x] [_ . y]] | |
(gte x y))) | |
(defne bounds [l m n] | |
([() _ _]) | |
([[h . t] m n] | |
(lte m h) | |
(gte n h) | |
(bounds t m n))) | |
(defne sudoku [puzzle] | |
([[s11 s12 s13 s14 | |
s21 s22 s23 s24 | |
s31 s32 s33 s34 | |
s41 s42 s43 s44]] | |
(bounds [s11 s12 s13 s14 | |
s21 s22 s23 s24 | |
s31 s32 s33 s34 | |
s41 s42 s43 s44] _1 _4) | |
(different [s11 s12 s13 s14]) | |
(different [s21 s22 s23 s24]) | |
(different [s31 s32 s33 s34]) | |
(different [s41 s42 s43 s44]) | |
(different [s11 s21 s31 s41]) | |
(different [s12 s22 s32 s42]) | |
(different [s13 s23 s33 s43]) | |
(different [s14 s24 s34 s44]) | |
(different [s11 s12 s21 s22]) | |
(different [s13 s14 s23 s24]) | |
(different [s31 s32 s41 s42]) | |
(different [s33 s34 s43 s44]))) | |
(run* [q] (sudoku [_3 _1 _2 _4 _4 _2 _3 _1 _1 _3 _4 _2 _2 _4 _1 _3])) |
数字の扱いが微妙なのでリストで数字を表してみました。
しかしこのコード、正しいパズルかどうかはテストしてくれますが、パズルを解決してくれません。
!=を使っているから・・・・?
まあ、まだまだ開発途中なので今後に期待です。