逻辑编程(又称关系范式)的突出优势是什么?因为该死的美学,逻辑编程简直太美了,他们自然的声明胜过于函数式编程中的任何宝石。逻辑编程使用搜索,这样能够就不会被算法细节牵着鼻子走,如果你还没有尝试过Prolog,关系编程简直无法让人想象。
学习关系范式最重要原因是因为它有趣。
swannodette/logic-tutorial提供了在Clojure 下学习逻辑编程的开源项目。
准备: 键入lein repl或cake repl 进入Cojure提示界面,输入: user=> (require 'clojure.core.logic) user=> (load "logic_tutorial/tut1") user=> (in-ns 'logic-tutorial.tut1) 这样就准备好了环境。
关系编程是问计算机问题,在问问题之前,我们需要计算机了解一些事实,比如男人。 tut1=> (defrel man x) #'tut1/man 然后定义几个不同名字的人: tut1=> (fact man 'Bob) nil tut1=> (fact man 'John) nil 然后我们就可以提问男人是谁?问问题使用run,希望计算机将可能的答案给q: tut1=> (run 1 [q] (man q)) (John)
我们刚才问了只有一个答案的问题,可以问超多个答案的问题: tut1=> (run 2 [q] (man q)) (John Bob)
如果问更多呢? tut1=> (run 3 [q] (man q)) (John Bob)
同样回答。这是因为我们已经告诉计算机这个世界上有两个男人,它不能给我们它不知道的。
下面让我们定义另外一种关系和事实: tut1=> (defrel fun x) #'tut1/fun tut1=> (fact fun 'Bob) nil 问一个新问题: tut1=> (run* [q] (man q) (fun q)) (Bob) 我们使用run*,这意味着所有这个问题的答案都会出现,问题是:谁是男人而且有趣。
再定义新的: tut1=> (defrel woman x) #'tut1/woman tut1=> (fact woman 'Lucy) nil tut1=> (fact woman 'Mary) nil tut1=> (defrel likes x y) #'tut1/likes
关系不一定有关单个实体,可以在事情之间定义关系: tut1=> (fact likes 'Bob 'Mary) nil tut1=> (fact likes 'John 'Lucy) nil tut1=> (run* [q] (likes 'Bob q)) (Mary) 我们可以问谁喜欢谁这样的关系问题。
tut1=> (run* [q] (likes 'Mary q)) () 却没有答案,因为我们没有说过Mary被谁喜欢,只有“Bob喜欢Mary”。
看看: tut1=> (fact likes 'Mary 'Bob) nil tut1=> (run* [q] (fresh [x y] (likes x y) (== q [x y]))) ([Mary Bob] [Bob Mary] [John Lucy])
这里fresh是 Clojure vector类似数组,存放谁喜欢谁很多可能值。
再看看: tut1=> (run* [q] (fresh [x y] (likes x y) (likes y x) (== q [x y]))) ([Mary Bob] [Bob Mary]) 只列出谁彼此喜欢的人。
完,有兴趣者可进入项目主页继续学习研究。