逻辑编程与函数编程的介绍
逻辑编程(又称关系范式)的突出优势是什么?因为该死的美学,逻辑编程简直太美了,他们自然的声明胜过于函数式编程中的任何宝石。逻辑编程使用搜索,这样能够就不会被算法细节牵着鼻子走,如果你还没有尝试过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])
只列出谁彼此喜欢的人。
完,有兴趣者可进入项目主页继续学习研究。