2020-06-29
Ann Ann
学习之前,请安装 Prolog 的运行环境 SWI-Prolog,才能运行后面的代码。
SWI-Prolog 官网有各个操作系统的二进制安装包,下载安装即可。Debian / Ubuntu 系统还可以用下面的命令。
$ sudo apt-get install swi-prolog
安装以后,Linux 系统可以命令行启动然后,启动即可。
$ swipl
?-
然启动以后,就进入了 Prolog 运行环境,?-
是命令提示符。下面是
运行一下 Hello world 的例子。
?- write("Hello, world").
Hello, world!
true.
上面命令输出 Hello world。
有几个地方需要注意。,write()
是输出命令,然后 Prolog 所有语句的结尾都用一个“点”(.
)表示语句结束。write()
是打印命令。这个命令本身就是一个表达式,输出完成以后,会返回值就是true.
,也会显示出来。
nl
是换行命令,如果想在 Hello world 之间插入一个换行,可以使用nl
命令下面的语句。
?- write('Hello,'), nl, write('world').
Hello,
world
true.
如果要退出 SWI-Prolog,可以使用halt
命令,别忘了后面还要加一个点。
?- halt.
Prolog 的变量和常量规则很简单:小写字母开头的字符串,就是常量;大写字母开头的字符串,就是变量。
?- write(abc).
abc
true.
?- write(Abc).
_3386
true.
上面代码中,abc
是常量,输出就是自身;Abc
是变量,输出就是该变量的值。
两个对象之间的关系,使用括号表示。比如,jack 的朋友是 peter,写成friend(jack, peter).
。
注意,jack 的朋友是 peter,不等于 peter 的朋友是 jack。如果两个人都认为对方是朋友,要写成下面这样。
friend(jack, peter).
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)
。
如果一条规则取决于多个条件同时为true
,则条件之间使用逗号分隔。
mother(X, Y) :- child(Y,X), female(X).
上面代码中,X
是Y
的母亲(mother(X, Y)
)取决于两个条件:Y
是X
的小孩,X
必须是女性。只有这两个条件都为true
,mother(X, Y)
才为true
。
如果一条规则取决于某个条件为false
,则在条件之前加上\+
表示否定。
onesidelove(X, Y) :- loves(X, Y), \+ loves(Y,X).
上面代码中,X
单相思Y
,取决于两个条件。第一个条件是X
喜欢Y
,第二个条件是Y
不喜欢X
。
Prolog 支持查询已经设定的条件。我们先写一个脚本hello.pl
。
friend(john, julia).
friend(john, jack).
friend(julia, sam).
friend(julia, molly).
然后在 SWI-Prolog 里面加载这个脚本。
?- [hello].
true.
上面代码中,true.
是返回的结果,表示加载成功。
然后,可以查询两个人是否为朋友。
?- friend(john, jack).
true.
?- friend(john, sam).
false.
listing()
函数可以列出所有的朋友关系。
?- listing(friend).
friend(john, julia).
friend(john, jack).
friend(julia, sam).
friend(julia, molly).
true.
还可以查询john
有多少个朋友。
?- friend(john, Who).
Who = julia ;
Who = jack.
上面代码中,Who
是变量名。任意的变量名都可以,只要首字母为大写。
下面看看 Prolog 如何解决实际问题。
我们知道,地图的相邻区域不能使用同一种颜色。现在有三种颜色:红、绿、蓝。请问如何为上面这幅地图着色?
首先,定义三种颜色。
color(red).
color(green).
color(blue).
然后,定义着色规则。
colorify(A,B,C,D,E) :-
color(A), color(B), color(C), color(D), color(E),
\+ A=B, \+ A=C, \+ A=D, \+ A=E,
\+ B=C, \+ C=D, \+ D=E.
上面代码中,colorify(A,B,C,D,E)
是一个对 ABCDE 五个变量求值的表达式。该表达式为true
的条件是,这五个变量各自为一种颜色,则相邻的变量不相等。
最后,这两段代码合在一起,组成一个脚本map.pl
,再加载这个脚本。
?- [map].
true.
执行表达式colorify(A,B,C,D,E)
,SWI-Prolog 就会将三种颜色依次赋值给变量,测试哪些组合是可能的结果。
?- colorify(A,B,C,D,E).
A = red,
B = D, D = green,
C = E, E = blue;
A = red,
B = D, D = blue,
C = E, E = green ;
A = green,
B = D, D = red,
C = E, E = blue ;
A = green,
B = D, D = blue,
C = E, E = red ;
A = blue,
B = D, D = red,
C = E, E = green ;
A = blue,
B = D, D = green,
C = E, E = red ;
可以看到,计算机给出了6组解,即有6种可行的地图着色方法。
下面看一个比较有趣的逻辑题。
Boddy 先生死于谋杀,现有六个嫌疑犯,每个人在不同的房间,每间房间各有一件可能的凶器,但不知道嫌疑犯、房间、凶器的对应关系。请根据下面的条件和线索,找出谁是凶手。
已知条件:六个嫌疑犯是三男(George、John、Robert)三女(Barbara、Christine、Yolanda)。
man(george). man(john). man(robert).
woman(barbara). woman(christine). woman(yolanda).
为了后面解题的方便,需要把“男人”和“女人”都定义为“人”。
person(X):- man(X).
person(X):- woman(X).
六个嫌疑犯分别待在六个房间:浴室(Bathroom)、饭厅(Dining Room)、厨房(Kitchen)、起居室(Living Room)、 储藏室(Pantry)、书房(Study)。每间房间都有一件可疑的物品,可以当作凶器:包(Bag)、火枪(Firearm)、煤气(Gas)、刀(Knife)、毒药(Poison)、绳索(Rope)。
location(bathroom). location(dining). location(kitchen).
location(livingroom). location(pantry). location(study).
weapon(bag). weapon(firearm). weapon(gas).
weapon(knife). weapon(poison). weapon(rope).
下面声明一条规则,每个房间的人都是不一样的。
uniq_ppl(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.
然后,定义一个表达式murderer(X)
,变量X
就是凶手。该表达式只有满足以下所有条件,才可能为true
。
murderer(X) :-
uniq_ppl(Bathroom, Dining, Kitchen, Livingroom, Pantry, Study),
uniq_ppl(Bag, Firearm, Gas, Knife, Poison, Rope),
注意,上面代码中Bathroom
和Bag
这样的字符串,都是大写字母开头,所以都是变量,代表对应的人。至于具体是谁,就要通过推理得到。
线索一:厨房里面是一个男人,那里的凶器不是绳索、刀子、包和火枪。
man(Kitchen),
\+Kitchen=Rope, \+Kitchen=Knife, \+Kitchen=Bag, \+Kitchen=Firearm,
线索二:Barbara 和 Yolanda 在浴室和书房。
woman(Bathroom), woman(Study),
\+christine=Bathroom, \+christine=Study,
\+barbara=Dining, \+barbara=Kitchen,
\+barbara=Livingroom, \+barbara=Pantry,
\+yolanda=Dining, \+yolanda=Kitchen,
\+yolanda=Livingroom, \+yolanda=Pantry,
线索三:带包的那个人不是 Barbara 和 George,也不在浴室和饭厅。
\+barbara=Bag, \+george=Bag,
\+Bag=Bathroom, \+Bag=Dining,
线索四:书房里面是一个带绳子的女人。
woman(Rope), Rope=Study,
线索五:起居室里面那件凶器,与 John 或 George 在一起。
man(Livingroom), \+Livingroom=robert,
线索六:刀子不在饭厅。
\+Knife=Dining,
线索七:书房和食品储藏室里面的凶器,没跟 Yolanda 在一起。
\+yolanda=Pantry, \+yolanda=Study,
线索八:George 所在的那间屋子里面,没有火枪。
Firearm=george,
线索九:Boddy 先生死在食品储藏室里,那里的凶器是煤气。
Pantry=Gas, Pantry=X, Gas=X,
线索就是上面这些,然后把写好的所有表达式放在一起,组成一个完整的脚本crime.pl
,代码看这里。
加载这个脚本,执行murderer(X)
函数,由于条件复杂,运算时间较长,最终会显示凶手是谁。
?- [crime].
true.
?- murderer(X).
KILLER IS :christine
Bathroom: yolanda
Dining: george
Livingroom: john
Pantry: christine
Study: barbara
Kitchen: robert
Knife: yolanda
Gas: christine
Rope: barbara
Bag: john
Poison: robert
Firearm: george
X = christine ;
IT Support 训练营01期
2025/11/10 06:13 (Sydney)
CCNA考证班01期
2025/09/06 08:37 (Sydney)
商业数据分析实战班第17期
2025/03/15 06:13 (Sydney)
地址
Level 10b, 144 Edward Street, Brisbane CBD(Headquarter)Level 2, 171 La Trobe St, Melbourne VIC 3000四川省成都市武侯区桂溪街道天府大道中段500号D5东方希望天祥广场B座45A13号Business Hub, 155 Waymouth St, Adelaide SA 5000Disclaimer
JR Academy acknowledges Traditional Owners of Country throughout Australia and recognises the continuing connection to lands, waters and communities. We pay our respect to Aboriginal and Torres Strait Islander cultures; and to Elders past and present. Aboriginal and Torres Strait Islander peoples should be aware that this website may contain images or names of people who have since passed away.
匠人学院网站上的所有内容,包括课程材料、徽标和匠人学院网站上提供的信息,均受澳大利亚政府知识产权法的保护。严禁未经授权使用、销售、分发、复制或修改。违规行为可能会导致法律诉讼。通过访问我们的网站,您同意尊重我们的知识产权。 JR Academy Pty Ltd 保留所有权利,包括专利、商标和版权。任何侵权行为都将受到法律追究。查看用户协议
© 2017-2024 JR Academy Pty Ltd. All rights reserved.
ABN 26621887572