博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
七周七语言——Prolog(二)
阅读量:4690 次
发布时间:2019-06-09

本文共 2847 字,大约阅读时间需要 9 分钟。

1  递归

首先来看一个知识库:
father(zeb,john_boy_sr).father(john_boy_sr,john_boy_jr).ancestor(X,Y):-father(X,Y).ancestor(X,Y):-father(X,Y),ancestor(Z,Y).
规则ancestor/2有两个子句。 如果一个规则由多个子句组成,那么其中一个子句为真,则这个规则为真。
下面我们来测试一下:
|?-ancestor(zeb,Who).Who=john_boy_sr?aWho=john_boy_jrno
这些都是以前就讲过的了,不多赘述。尤其要强调的是: 每个递归的子目标都会使用栈空间,最终你很可能会耗尽栈空间。声明式语言通常使用一种称为
尾递归优化的技术来解决这个问题。 如果你将一个递归的子目标放到递归规则的末尾,Prolog会通过丢弃调用栈来优化这次调用,并保持内存占用不变。这里的调用就是一个尾递归,因为递归子目标ancestor(Z,Y)是递归规则中的最后一个目标。

2  列表和元组

可以用[1,2,3]来指定一个
列表,也可以用(1,2,3)来指定一个
元组。列表是
变长容器,而元组则是
定长容器

合一,第二部分

|?-(A,B,C)=(1,2,3).A=1B=2C=3yes|?-[2,2,3]=[X,X,Z].X=2Z=3yes
例子很简单。列表拥有一项元组不具备的能力,即你可以通过
[Head|Tail]解构列表。当你将一个列表与这种结构合一时,Head将绑定列表的第一个元素,而Tail将绑定剩余元素,像这样:
|?-[a,b,c]=[Head|Tail].Head=aTail=[b,c]yes
注意, [Head|Tail]不能与一个空列表合一,不过单元素列表可以。
|?-[]=[Head|Tail].no|?-[a]=[Head|Tail].Head=aTail=[]yes
再来看两个复杂的例子:
|?-[a,b,c]=[a|Tail].Tail=[b,c]yes|?-[a,b,c]=[a|[Head|Tail]].Head=bTail=[c]yes|?-[a,b,c,d,e]=[_,_|[Head|_]].Head=cyes
“_”是一个通配符,可以与任何对象合一。

3  列表与数学运算

count(0,[]).count(Count,[Head|Tail]):-count(TailCount,Tail),Count is TailCount+1.sum(0,[]).sum(Total,[Head|Tail]):-sum(Sum,Tail),Total is Head+Sum.average(Average,List):-sum(Sum,List),count(Count,List),Average is Sum/Count.
这些规则很简单。下面逐步说明他们的工作方式。
  • 发起查询count(What,[1]),由于列表非空,无法与第一个规则合一。继续满足第二个规则count(Count,[Head|Tail])中的目标。进行合一操作,What绑定为Count,Head绑定为1,Tail绑定为[]。
  • 和以后,第一个目标变为count(TailCount,[]),我们尝试证明这个子目标。这次,我们与第一条规则进行合一。TailCount绑定为0。现在第一个规则满足了,所以接下来处理第二个目标。
  • 现在,对Count的求值为TailCount+1。我们可以合一变量。TailCount绑定为0,因此将Count绑定为0+1或1.
其他类似,不再赘述。

4  两个方向上使用规则

下面我们讨论
append规则。如果List3为List1+List2,那么规则append(List1,List2,List3)为真。
|?-append([oil],[water],[oil,water]).yes|?-append([oil],[water],[oil,slick]).no
下面是一个列表构造器:
|?-append([tiny],[bubbles],What).What=[tiny,bubbles]yes
下面的代码用于列表减法操作:
|?-append([dessert_topping],Who,[dessert_topping,floor_wax]).Who=[floor_wax]yes
下面的代码用于计算出可能的排列:
|?-append(One,Two,[apples,oranges,bananas]).One=[]Two=[apples,oranges,bananas]?aOne=[apples]Two=[oranges,bananas]One=[apples,oranges]Two=[bananas]One=[apples,oranges,bananas]Two=[]no
下面我们来看一下实现append需要多少代码。重新实现Prolog的append,不过将它称为concatenate。步骤如下:
  • 编写一个规则concatenate(List1,List2,List3),它可以将一个空列表与List1连接在一起。
  • 添加一个规则,它可以将List1中的一个元素与List2连接在一起。
  • 添加一个规则,它可以将List1中的两个元素或三个元素与List2连接在一起。
  • 看看我们可以泛化哪些东西。
代码如下:
concatenate([],List,List).concatenate([Head|[]],List,[Head|List]).concatenate([Head1|[Head2|[]]],List,[Head1,Head2|List]).concatenate([Head1|[Head2|[Head3|[]]]],List,[Head1,Head2,Head3|List]).
这只是前面提到的简单规则的使用,不赘述,下面看一个使用了嵌套规则的concatenate:
concatenate([],List,List).concatenate([Head|Tail1],List,[Head|Tail2]):-concatenate(Tail1,List,Tail2).
这段代码非常简单,首先, 判断第一个列表是否为空,如果为空并且第二个和第三个列表系统,那么规则为真,这表明将一个空列表与List连接在一起,你将得到那个List。第二个子句表明如果List1和List3的Head相同,并且你可以证明将List1的Tail和List2连接在一起将得到List3的Tail,那么将List1和List2连接在一起将会得到List3。
欢迎大家留言讨论,共同进步!

 

转载于:https://www.cnblogs.com/snake-hand/p/3181447.html

你可能感兴趣的文章
FansUnion:共同写博客计划终究还是“流产”了
查看>>
python 二维字典
查看>>
编译原理实验一
查看>>
Git for Android Studio 学习笔记
查看>>
pip 警告!The default format will switch to columns in the future
查看>>
Arrays类学习笔记
查看>>
实验吧之【天下武功唯快不破】
查看>>
2019-3-25多线程的同步与互斥(互斥锁、条件变量、读写锁、自旋锁、信号量)...
查看>>
win7-64 mysql的安装
查看>>
dcm4chee 修改默认(0002,0013) ImplementationVersionName
查看>>
maven3在eclipse3.4.2中创建java web项目
查看>>
发布时间 sql语句
查看>>
黑马程序员 ExecuteReader执行查询
查看>>
记一些从数学和程序设计中体会到的思想
查看>>
题目1462:两船载物问题
查看>>
POJ 2378 Tree Cutting(树形DP,水)
查看>>
第二冲刺阶段个人博客5
查看>>
UVA 116 Unidirectional TSP (白书dp)
查看>>
第三方测速工具
查看>>
MySQL 网络访问连接
查看>>