七周七语言——Prolog(二)

2023-05-16

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?a

Who=john_boy_jr

no

这些都是以前就讲过的了,不多赘述。尤其要强调的是: 每个递归的子目标都会使用栈空间,最终你很可能会耗尽栈空间。声明式语言通常使用一种称为 尾递归优化的技术来解决这个问题。 如果你将一个递归的子目标放到递归规则的末尾,Prolog会通过丢弃调用栈来优化这次调用,并保持内存占用不变。这里的调用就是一个尾递归,因为递归子目标ancestor(Z,Y)是递归规则中的最后一个目标。

2  列表和元组

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

合一,第二部分

|?-(A,B,C)=(1,2,3).

A=1
B=2
C=3

yes
|?-[2,2,3]=[X,X,Z].

X=2
Z=3

yes
例子很简单。列表拥有一项元组不具备的能力,即你可以通过 [Head|Tail]解构列表。当你将一个列表与这种结构合一时,Head将绑定列表的第一个元素,而Tail将绑定剩余元素,像这样:
|?-[a,b,c]=[Head|Tail].

Head=a
Tail=[b,c]

yes

注意, [Head|Tail]不能与一个空列表合一,不过单元素列表可以。
|?-[]=[Head|Tail].

no
|?-[a]=[Head|Tail].

Head=a
Tail=[]

yes
再来看两个复杂的例子:
|?-[a,b,c]=[a|Tail].

Tail=[b,c]

yes
|?-[a,b,c]=[a|[Head|Tail]].

Head=b
Tail=[c]

yes
|?-[a,b,c,d,e]=[_,_|[Head|_]].

Head=c

yes

“_”是一个通配符,可以与任何对象合一。

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]?a

One=[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。
欢迎大家留言讨论,共同进步!

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

七周七语言——Prolog(二) 的相关文章

  • 使用失败、回溯 Prolog 查找列表的最小值

    我想使用导致回溯的失败来计算列表的最小值 我如何改变分钟 分钟 X 分钟 以使其工作 min X A B X is the min of A B min X X Y X lt Y min Y X Y Y lt X member X X me
  • 使用 Prolog 中的累加器计算多项式的计算问题

    背景 我需要编写一个谓词 eval P A R 其中 P表示多项式系数列表 即1 2x 3x 2表示为 1 2 3 A 代表 X 的值 R 是 X A 处多项式的结果 Example eval 3 1 2 3 R 产生 R 24 编辑 之前
  • 序言排列函数

    我是 Prolog 的新手 我知道排列的递归函数 即 per per L X P del X L L1 per L1 P 我想知道当我们收到时这个函数在最后一次迭代中的逻辑树per 它返回哪个元素 Sonia 您还没有给我们 del 谓词
  • 多个事实的聚合解决方案

    尝试创建一个谓词 timePeriod 2 计算特定事实的两个日期之间的时间段 我已经设法自己做到这一点 但当 其他答案 存在于同一列表中时会遇到问题 即更容易用示例解释 我有以下知识基础事实 popStar Jackson 1987 19
  • Smullyan 数值机的解决方案

    在这里我建议找到 Smullyan 数值机的解决方案 此处定义 http heras gilsanz com manuel smullyan machines html 问题陈述 它们是接受数字列表作为输入 并根据输入模式遵循一些规则将其转
  • Prolog:覆盖谓词和使用它之间的区别

    我觉得自己真的很愚蠢 感觉自己错过了一些东西 我基本上有两个文件 module pl通用逻辑规则 可重用 state pl一个针对当前场景 在模块文件中 module pl 我已经声明 inside Food Eater T isTime
  • 函数式语言中的多线程? (序言)

    当我的朋友在学校开始学习 Prolog 时 我嘲笑他学习了一门无用的语言 然而 他向我展示了一些我从来不知道可能发生的东西 我想知道这个技术从何而来 技术是这样的 permutation List isAMember X List dele
  • Prolog 追加与剪切运算符

    当我们使用append和cut操作符时会出现什么问题 append2 L L append2 H T L H TL append2 T L TL 我尝试了几种不同的输入 但总是成功 append2 1 2 5 L L 1 2 5 appen
  • 针对数字板难题的优化 CLP(FD) 求解器

    考虑问题从https puzzling stackexchange com questions 20238 explore the square with 100 hops https puzzling stackexchange com
  • 如何在Prolog中编写cmp_list/3函数?

    Write a predicate cmp list 3 the first 2 arguments are 2 lists and the last one is Comparison which means ge lt le or gt
  • 求解序言中极其简单的方程:A = B + C?

    我有一个非常简单的方程 我希望能够在序言中求解 A B C 我希望能够编写一个谓词来表达这种关系 它可以处理任何一个未实例化的参数 无需推广到更复杂的关系或方程 myEquation A B C something 我可以使用以下语义进行调
  • 如何在 Prolog 中计算数字序列的和

    任务是计算从0到M的自然数之和 我使用SWI Prolog编写了以下代码 my sum From To From gt To my sum From To S From 0 Next is 1 S is 1 my sum Next To S
  • Prolog 实现 and/2、or/2、nand/2、nor/2、xor/2 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想在序言中实现以下谓词并将它们用于真值表 and 2 or 2 nand 2 nor 2 xor 2 也许有人可以告诉我如何实现和
  • 转换句子会产生无限循环 - 但如何转换呢?

    我不明白这是哪里出了问题 请注意 我对 Prolog 很陌生 我确信我错过了一些东西 只是不知道那可能是什么 有人可以帮我吗 谢谢 这是我的代码 printSentence printSentence W write W write nl
  • 列表中的连续元素

    我正在阻止一个谓词来编码Prolog 我需要对两个谓词进行编码 如果我打电话 u a b c d e f X 它会给X a b X b c X c d 如果我打电话 v a b c d e f X 它会给X a b X c d X e f
  • 控制 Prolog 变量值选择

    灵感来自之前的一个问题 https stackoverflow com questions 41595786 using operator to save variables in a list我尝试实现一些可以枚举布尔表达式可能性的东西
  • Prolog 罗马数字(属性语法)

    我正在做一项作业prolog questions tagged prolog扫描数字列表并应返回该列表是否是有效的罗马数字以及数字的十进制值 前任 1 roman N I N 1 true 2 当我运行我认为应该工作的程序时 十进制值总是正
  • 实现用户定义的算术函数

    如何添加函数 例如汉明权重 并在右侧出现的表达式中使用它是一些 is 2 goal 像 goal expansion 或 term expansion 这样的东西可以帮助这里吗 我承认这不是一个大功能 但它可以提高我的一些 Prolog 程
  • 根据一个值找到列表内列表的最小值

    我在序言中有这个列表 dublin london 1000 dublin moscow london 5000 我想计算列表的最小值 这样答案应该是 dublin london 1000 这个问题有一些类似的问题序言中列表列表中的最小值 h
  • 谓词对于列表中的所有元素都必须为 true

    我有一组事实 likes john mary likes mary robert likes robert kate likes alan george likes alan mary likes george mary likes har

随机推荐