Prolog简介
部分资料来自于:
http://www.ruanyifeng.com/blog/2019/01/prolog.html
https://blog.csdn.net/laoyao_legend/article/details/84870827
Prolog是一款面向逻辑问题的编程软件(不是离散要求的话,我估计我到死都不会接触这一款)
比如,"苏格拉底是人,人都会死,所以苏格拉底会死"这一类的问题。
只要给定事实和规则,它会自动分析其中的逻辑关系,然后允许用户通过输入和查询,完成复杂的逻辑运算。
(底层估计是强连通分量或者暴力枚举的实现吧,类似于2-SAT问题?不纠结,用就完事了)
运行环境 SWI-Prolog
基本框架
运行模块
这是在程序运行阶段,你要进行输入,输入的是命令
脚本编辑模块
这是在程序运行之前所要预加载的脚本,你在其中要写定逻辑规则和事实,作为运行基础
语法部分
基本格式
开头以"?-"作为命令提示符,表示某个程序的开始
所有语句均以"."作为结束标志
单独语句中有多个命令用","分隔
退出可使用halt命令
输入输出
1)输出语句:write()
下面展示的是经典程序
?- write("Hello, world").
Hello, world!
true.
注意为什么会有多打印个true呢?
Prolog中的命令本身就是一个表达式,命令完成以后,会返回值,并且显示出来
2)换行命令nl:
?- write('Hello,'), nl, write('world').
Hello,
world
true.
3)输入语句read(变量名)
后面具体脚本在谈怎么用
变量&常量
变量和常量规则很简单:小写字母开头的字符串,就是常量;大写字母开头的字符串,就是变量
?- write(abc).
abc
true.
?- Abc=1,write(Abc).
1
Abc = 1.
关系
两个对象之间的关系,使用括号表示。比如,Jack 的朋友是 Peter,写成
friend(jack, peter).
关系名(A,B)值A对于B是什么/A是B的什么
这里仅代表单向关系, 如果表示双向关系
friend(jack,prter).
friend(peter,jack).
如果括号里面只有一个参数,就表示对象拥有该属性,比如 Jack 是男性,写成male(jack).
规则
规则是推理方法,即如何从一个论断得到另一个论断。
friend(X, Y):-friend(Y,X).
长得比较有内涵的符号":-"表示推理关系
上面代码中,X和Y都是大写,表示这是两个变量。
含义是只要右边的表达式friend(Y, X)为true,那么左边的表达式friend(X, Y)也为true。
因此,根据这条规则,friend(Jack, Peter)就可以推理得到friend(Peter, Jack)。
如果一条规则取决于多个条件,可以使用逗号分隔,如
mother(X, Y) :- child(Y,X), female(X).
注意在Prolog中,非用符号"+"进行表示
以及在规则设定可以面向多元如,color(A,B,C),differ(A,B,C,D)
在具体编程中,
关系的声明一般使用常量,表示具体的内容满足什么属性。而规则一般使用的是变量,表示抽象出来的对象应有什么属性
当你进行查询的时候,计算机无非是尝试对规则下抽象对象赋以具体值,也就是求抽象对象的可行解
查询
Prolog支持查询已经设定的条件
比如我们在脚本里面写了friend这个规则,我们就可以进行查询
如:查询john有多少个朋友
?- friend(john, Who).
Who = julia ;
Who = jack.
注意如果有多种情况,可以键入“;”查看下一组赋值情况
Who是抽象的,它具体是多少,计算机尝试去给它赋具体值,julia是一个可行解,jack也是一个可行解,它就会输出
函数listing(关系),用于列出所有使关系的元素
如:
?- listing(friend).
friend(john, julia).
friend(john, jack).
friend(julia, sam).
friend(julia, molly).
true.
例子:
注意:prolog不支持中文,我在Nodepad++上进行编辑,实际脚本没有以下中文批注
/*
作者:tsy
@Written by tsy
建模思路分析:
我们要找到凶手
这一逻辑问题要落脚于建立正确的匹配关系,即谁拥有什么物品,在哪个房间
Prolog的编程要求我们区分清楚抽象对象和具体对象,那我们如何选定嘞?
当我们讨论什么物品,还是什么房间的时候,我们论述的展开都是建立在“人”之上的,
即我们可以理解成拥有什么物品的人,在什么房间的人,论述的主体始终离不开“人”
所以我们要将物品对应的人,以及房间对应的人,抽象出来,作为变量(大写),求解的正是这些 变量的解情况
而这些可行解应该从具体的人中进行选择,故人名应该看作常量(小写)
*/
//前置条件(1):三男三女,均为常量
man(george).
man(john).
man(robert).
woman(barbara).
woman(christine).
woman(yolanda).
person(X):-man(X).
person(X):-woman(X).
//抽象的事物与具体的人只能一一建立匹配关系,即所有解不能出现相同的
differ(A,B,C,D,E,F):-
person(A),person(B),person(C),person(D),person(E),person(F),
+A=B,+A=C,+A=D,+A=E,+A=F,
+B=C,+B=D,+B=E,+B=F,
+C=D,+C=E,+C=F,
+D=E,+D=F,
+E=F.
//前置条件(2)&&前置条件(3):
murderer(X):-
differ(Bathroom,Diningroom,Kitchen,Livingroom,Pantry,Study),
differ(Bag,Firearm,Gas,Knife,Poison,Rope),
//线索一:厨房里面是一个男人,里面的凶器不是绳索、刀子、包、毒药
man(Kitchen),
+Kitchen=Rope,
+Kitchen=Knife,
+Kitchen=Bag,
+Kitchen=Firearm,
//线索二:Barbara 和 Yolanda 在浴室和书房,好好理解这句话的意思,我一开始搞错了
woman(Bathroom), woman(Study),
+Bathroom=christine, +Study=christine,
+Diningroom=barbara, +Kitchen=barbara,
+Livingroom=barbara, +Pantry=barbara,
+Diningroom=yolanda, +Kitchen=yolanda,
+Livingroom=yolanda, +Pantry=yolanda,
//线索三:带包的那个人不是 Barbara 和 George,也不在浴室和饭厅
+Bag=barbara,
+Bag=george,
+Bag=Bathroom,
+Bag=Diningroom,
//线索四:书房里面是一个带绳子的女人
woman(Rope),
Rope=Study,
//线索五:起居室里面那件凶器,与 John 或 George 在一起。注意John和George都是男人,故可将后半句转义。
man(Livingroom),
+Livingroom=robert,
//线索六:刀子不在饭厅
+Knife=Diningroom,
//线索七:书房和食品储藏室里面的凶器,没跟 Yolanda 在一起
+Study=yolanda,
+Pantry=yolanda,
//线索八:George所在的那间屋子有火枪
Firearm=george,
//线索九:Boddy 先生死在食品储藏室里,那里的凶器是煤气
Pantry=Gas,
X=Gas.
运行结果
我这里键入了分号让他输出下一组可行解
结果flase,说明christine是唯一的可行解
注意可能脚本编译会warning:Poison这个没有添加任何约束条件,但代码能跑
为了美观我在脚本里面加了Poison=Poison