Prolog语言知识推理系列文章,不同编程语言有着不同编程视角,JAVA是面向对象,Nodejs是异步回调,R语言是统计算法,Prolog就是知识推理。每种语言都是独特的,如果想把一门语言学好用好,关键是利用语言的特点,做对的事情。
本系列文章主要介绍Prolog语言,从入门安装到知识推理。Prolog是完全不一样的,他没有复杂的程序结构,也不是为了解决算法问题,而是专注于逻辑推理,擅长解决抽象的问题。
关于作者:
- 张丹,分析师/程序员/Quant: R,Java,Nodejs
- blog: http://fens.me
- email: bsspirit@gmail.com
转载请注明出处:
http://blog.fens.me/prolog-family/
前言
最近在研究逻辑推理的一些问题,无意中发现了一门编程语言prolog就是解决推理问题的。家族关系是社会生活中一个重要的组成元素,每个人都有自己的家族关系网,这种关系结构并不是很容易地表达,而且人物关系一旦多了,会非常地复杂。
试试prolog的在推理上的强大之处,能否帮我们解决复杂的社会问题的推理计算过程。
目录
- 家族关系定义
- 用prolog表达家族关系
- 推理计算
1. 家族关系定义
我们虚拟一个家族关系,共16个人,8男8女,包括几个不同的维度关系,性别,家长,孩子,结婚,兄弟,姐妹等,如下图所示。
上图注释:
- 性别特征:男为蓝色方形,女为橙色圆形。
- 家长关系:用蓝色箭头表示,箭头的开始为家长,箭头的指向为孩子。
- 婚姻关系:用红色连线表示,两端为结婚的男性和女性。
2. 用prolog表达家族关系
我们首先建立一个prolog的文件叫family.pl,在family.pl中定义关系的定义,如果直接在prolog的运行环境中运行代码代码,则会出现DWIM could not correct goal的错误,错误解决请参考文章prolog语言安装
新建文件family.pl。在window中可以直接在任何文本编辑器中,新建一个文件。
~ notepad c:/work/prolog/02 family/family.pl
根据prolog语言的语法结构,我们需要在编程时,分别定义事实(Fact)、规则(Rule)和问题(Question)。
- 事实,就是把具体的对象进行语言表达和描述。
- 规则,就是建立对象之间的关系。
- 问题,就是用prolog来找答案。
事实:建立对象的性别特征,女性和男性。
% female: a,c,i,k,m,e,g,o
% male: b,d,j,l,n,f,h,p
female(a).
female(c).
female(i).
female(k).
female(m).
female(e).
female(g).
female(o).
male(b).
male(d).
male(j).
male(l).
male(n).
male(f).
male(h).
male(p).
规则:建立家长关系
% parent
parent(a,d).
parent(a,j).
parent(b,d).
parent(c,m).
parent(c,n).
parent(d,m).
parent(d,n).
parent(d,g).
parent(e,g).
parent(e,h).
parent(f,h).
parent(g,o).
parent(i,k).
parent(i,l).
parent(j,k).
parent(j,l).
规则:建立婚姻关系
% married
married(a,b).
married(c,d).
married(i,j).
married(e,f).
married(o,p).
通过上面的代码,我们就让这个家族关系的事实和基本规则建立完成了。
3. 推理计算
接下来,我们就可以进行关系的计算了。我们只需要提出问题,让程序自动实现推理计算的过程。
首先需要打开prolog运行环境,然后加载刚写的family.pl脚本文件。
# 启动 prolog运行环境
~ swipl
# 设置工作路径
?- cd("c:/work/prolog/02 family/").
true.
# 加载脚本
?- [family].
true.
问题1:a是谁的家长
?- parent(a,Who).
Who = d ;
Who = j.
a是我们之前定义好的常量,Who是变量,用Who表达结果。得出a是d和j的家长。
问题2:d是谁的孩子
?- parent(Who,d).
Who = a ;
Who = b.
通过家长的反向规则,可计算出孩子。
我们可以新建一个规则:建立孩子关系,家长关系的反向关系。
child(X,Y) :- parent(Y,X).
重新加载family.pl文件再运行。
?- child(d,Who).
Who = a ;
Who = b.
问题3:g的爸爸是谁?
需要满足2个条件,是g的家长,同时是男性。
?- parent(X,g),male(X).
X = d .
我们可以新建一个规则:建立父子关系和母子关系。
% mother, father
mother(X,Y) :- parent(X,Y),female(X).
father(X,Y) :- parent(X,Y),male(X).
g的爸爸和g的妈妈。
% g的爸爸
?- father(Who,g).
Who = d .
% g的妈妈
?- mother(Who,g).
Who = e.
问题4:e和f结婚了吗?
结婚是一个双方关系,需要计算e和f是否结婚,同时还需要判断f和e是否结婚。
?- married(e,f).
true.
?- married(f,e).
false.
我们需要建立f和e的新规则:建立双向的婚姻关系。
% 建立双向的婚姻关系
married(X,Y) :- married(Y,X).
重新加载后,计算f和e的婚姻规则。
?- married(f,e).
true .
问题5:谁是亲姐妹,谁是亲兄弟
谁是亲姐妹,设X和Y是亲姐妹,Z是X和Y的家长,X和Y都是女性,X不是Y。
?- parent(Z,X),parent(Z,Y),female(X),female(Y), \+ X=Y.
Z = d,
X = m,
Y = g ;
Z = d,
X = g,
Y = m ;
false.
计算得出X=m和Y=g是亲姐妹,她们的家长是Z=d。
那么,谁是亲兄弟?设X和Y是亲兄弟,Z是X和Y的家长,X和Y都是男性,X不是Y。
?- parent(Z,X),parent(Z,Y),male(X),male(Y), \+ X=Y.
Z = a,
X = d,
Y = j ;
Z = a,
X = j,
Y = d ;
false.
计算得出X=d和Y=j是亲兄弟,她们的家长是Z=a。
新加新规则:建立兄弟和姐妹的关心。
sister(X,Y) :- parent(Z,X),parent(Z,Y),female(X),female(Y), \+ X=Y.
brother(X,Y) :- parent(Z,X),parent(Z,Y),male(X),male(Y), \+ X=Y.
问题6:祖父母,姥姥姥爷,爷爷奶奶
在英语里祖父母似乎是不分的,都叫grandparent,而在汉语里妈妈的父母是姥姥和姥爷,爸爸的父母是爷爷和奶奶,规则有所不同。
直接新规则:
% grandparent
grandparent(X,Y) :- parent(X,Z),parent(Z,Y).
% yeye,nainai
yeye_nainai(Y,X) :- father(Z,X),parent(Y,Z).
% laolao,laoye
laolao_laoye(Y,X) :- mother(Z,X),parent(Y,Z).
重新加载程序:o的祖父母是谁?
?- grandparent(Y,o).
Y = d ;
Y = e ;
false.
o的姥姥和姥爷是谁?
?- laolao_laoye(Y,o).
Y = d ;
Y = e.
n的爷爷和奶奶是谁?
?- yeye_nainai(Y,n).
Y = a ;
Y = b.
其实,可以找的关系还有很多,比如表兄妹,姑姑,婶婶,舅舅,姨夫等,同时我们也可以增加其他维度的内容,比如同在一所大学,谁与谁曾经结婚又离婚了,孩子谁在抚养等多种逻辑上复杂的问题。
本文的完整代码,可以在github上找到:https://github.com/bsspirit/prolog-learning/tree/main/02 family
同样,本文还是对于prolog的初探,进行逻辑推理,从浅入入深的过程,希望本文能让所有的prolog新手快速上手。
转载请注明出处:
http://blog.fens.me/prolog-family/