prolog - prolog 中的 Zebra 解决方案如何工作?
问题描述
zebra_owner(Owner) :-
houses(Hs),
member(h(Owner,zebra,_,_,_), Hs).
water_drinker(Drinker) :-
houses(Hs),
member(h(Drinker,_,_,water,_), Hs).
houses(Hs) :-
length(Hs, 5), % 1
member(h(english,_,_,_,red), Hs), % 2
member(h(spanish,dog,_,_,_), Hs), % 3
member(h(_,_,_,coffee,green), Hs), % 4
member(h(ukrainian,_,_,tea,_), Hs), % 5
adjacent(h(_,_,_,_,green), h(_,_,_,_,white), Hs), % 6
member(h(_,snake,winston,_,_), Hs), % 7
member(h(_,_,kool,_,yellow), Hs), % 8
Hs = [_,_,h(_,_,_,milk,_),_,_], % 9
Hs = [h(norwegian,_,_,_,_)|_], % 10
adjacent(h(_,fox,_,_,_), h(_,_,chesterfield,_,_), Hs), % 11
adjacent(h(_,_,kool,_,_), h(_,horse,_,_,_), Hs), % 12
member(h(_,_,lucky,juice,_), Hs), % 13
member(h(japanese,_,kent,_,_), Hs), % 14
adjacent(h(norwegian,_,_,_,_), h(_,_,_,_,blue), Hs), % 15
member(h(_,_,_,water,_), Hs), % one of them drinks water
member(h(_,zebra,_,_,_), Hs). % one of them owns a zebra
adjacent(A, B, Ls) :- append(_, [A,B|_], Ls).
adjacent(A, B, Ls) :- append(_, [B,A|_], Ls).
如果列表实际上一直是空的,为什么houses(Hs)
谓词不会通过各种检查?member(elem, list)
我知道这听起来可能是个愚蠢的问题,但围绕 Prolog 进行思考实际上很难,尤其是在多年的面向对象编程之后。任何帮助表示赞赏!
编辑:我没有提到我问序言的查询,就是这个zebra_owner(Owner)
编辑2:还发布问题的文本(有点著名)以供参考:
- 一排五座彩色的房子,每座都有一个主人、一只宠物、香烟和一杯饮料。
- 英国人住在红房子里。
- 西班牙人有一条狗。
- 他们在温室里喝咖啡。
- 乌克兰人喝茶。
- 绿房子紧挨着白房子。
- 温斯顿吸烟者有一条蛇。
- 在黄色的房子里,他们抽 Kool。
- 在中间房子里,他们喝牛奶。
- 挪威人住在左边第一个房子里。
- 切斯特菲尔德吸烟者住在养狐狸的人附近。
- 在有马的房子附近的房子里,他们抽着库尔。
- Lucky Strike 吸烟者喝果汁。
- 日本人抽肯特。
- 挪威人住在蓝屋附近。
谁拥有斑马,谁喝水?
解决方案
如果列表实际上一直是空的,Houses(Hs) 谓词为什么不会通过各种成员(elem,list)检查?
那是因为列表实际上不是空的!Prolog 中的空列表是[]
. 它不包含任何元素。
但是调用中的列表houses(Hs)
由该谓词中的第一个目标控制,即length(Hs, 5)
. 这个目标是什么意思?
了解 Prolog 的重要一点是,目标或查询不仅仅意味着“这个陈述是真的吗?”。Prolog 目标或查询意味着“在什么情况下这个陈述是真实的?”。Prolog 将尝试向您描述使您的查询为真的情况。
因此,即使我们之前完全不知道Hs
,在执行这个length
查询时,GNU Prolog 会说:
| ?- length(Hs, 5).
Hs = [_,_,_,_,_]
如果是 形式,那么length(Hs, 5)
就变为真。这不是一个空列表。它甚至不是一个可能为空的列表。这是一个绝对包含五个元素的列表。我们对这些元素一无所知!但是列表的长度绝对是固定的。 Hs
[_, _, _, _, _]
也许你被 Prolog 允许你谈论一个肯定有元素但其元素还不知道的列表的事实误导了。这是典型的面向对象语言中不可能实现的概念。但我们不知道元素的事实并不意味着那里什么都没有,即列表是空的。
至于member
调用如何成功:同样,它们不仅仅是检查“是”X
的成员Hs
。它们是问题,意思是“在什么情况下是X
成员Hs
?”。同样,Prolog 会为您做一些工作来描述这些情况:
| ?- length(Hs, 5), member(x, Hs).
Hs = [x,_,_,_,_] ? ;
Hs = [_,x,_,_,_] ? ;
Hs = [_,_,x,_,_] ? ;
Hs = [_,_,_,x,_] ? ;
Hs = [_,_,_,_,x]
x
的成员也是如此,Hs
如果x
是 的第一个元素Hs
,或者第二个,或者第三个,等等。在每种情况下,“描述情况”意味着 Prolog 实际上将列表的适当元素(之前是一个变量)绑定到元素x
。对于这些可能性中的每一个,member
目标之后的进一步计算可以进一步实例化列表。这就是建立斑马谜题解决方案的原因:Prolog 建立了一个实际描述解决方案的数据结构,而不只是对“这个难题有解决方案”这个问题回答“是”。
推荐阅读
- python - 未找到带有参数 '('',)' 的 'equipment_categories' 的反向操作。尝试了 1 种模式:['equipments/equipment_categories/$']
- r - 使用额外条件 r 合并数据帧
- list - 颤振我如何从其他文件加载列表?
- ignite - 点燃缓存 - 仅在满足条件时更新缓存条目的原子操作
- logging - 如何在 BlueZ 的 meshctl 中生成日志打印?
- database - 经过身份验证的开发用户无法在模拟器中写入/创建到 CloudKit 公共数据库
- parallel-processing - 用 MPI_ISEND 和 fortran 拆分数组的问题
- magento - 将所有未显示在 magento 2 产品目录中的值归因
- python - 异常处理:用于捕获异常的 finally-like 习惯用法
- css - 如何在反应中更改抽屉组件materialui的背景颜色?