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,尤其是在多年的面向对象编程之后。感谢您的帮助!
编辑:我没有提到我问prolog的问题,就是这个zebra_owner(Owner)
编辑2:也张贴问题的文本(有点著名(供参考:
- 五种颜色的房子排成一排,每个房子都有一个主人、一只宠物、香烟和一杯饮料
- 英国人住在红房子里
- 西班牙人养了一只狗
- 他们在温室里喝咖啡
- 乌克兰人喝茶
- 绿色的房子在白色的房子旁边
- 温斯顿吸烟者有一条蛇
- 在黄色的房子里,他们抽库尔
- 在中间的房子里,他们喝牛奶
- 挪威人住在左边第一栋房子里
- 切斯特菲尔德的烟鬼住在带狐狸的男人附近
- 在房子附近的房子里,他们和马一起抽库尔
- 幸运一击吸烟者喝果汁
- 日本人抽烟
- 挪威人住在蓝色的房子附近
谁拥有斑马,谁喝水?
如果列表实际上一直是空的,Houses(Hs(谓词为什么不通过各种成员(elem,list(检查?
这是因为列表实际上并不是空的!Prolog中的空列表是[]
。它不包含任何元素。
但是,对houses(Hs)
的调用中的列表由该谓词中的第一个目标(即length(Hs, 5)
(控制。这个目标意味着什么?
了解Prolog的一个重要方面是,目标或查询不仅仅意味着";这个说法是真的吗&";。Prolog目标或查询意味着">在什么情况下这句话是真的吗&";。Prolog将尝试向您描述您的查询成为真的情况。
因此,即使我们以前对Hs
一无所知,在执行这个length
查询时,GNU Prolog会说:
| ?- length(Hs, 5).
Hs = [_,_,_,_,_]
如果Hs
的形式为[_, _, _, _, _]
,则length(Hs, 5)
变为真。这不是一个空列表。它甚至不是一个可能为空的列表。这是一个明确包含五个元素的列表。我们对这些元素一无所知!但名单的长度是固定的。
Prolog允许你谈论一个肯定有元素但元素未知的列表,这可能会误导你。这是一个在典型的面向对象语言中不可能实现的概念。但是,我们不知道这些元素并不意味着那里什么都没有,也就是说,列表是空的。
至于member
调用是如何成功的:同样,它们不仅仅是检查";CCD_ 13是CCD_;。这些问题的意思是">在什么情况下X
是Hs
的成员&";。再次,Prolog将为您做一些工作来描述这些情况:
| ?- length(Hs, 5), member(x, Hs).
Hs = [x,_,_,_,_] ? ;
Hs = [_,x,_,_,_] ? ;
Hs = [_,_,x,_,_] ? ;
Hs = [_,_,_,x,_] ? ;
Hs = [_,_,_,_,x]
因此,如果x
是Hs
的第一个元素,或者第二个元素,或第三个元素,等等,则x
是Hs
的成员;描述情况";意味着Prolog实际上将列表的适当元素(之前是变量(绑定到元素CCD_ 21。对于这些可能性中的每一种,member
目标之后的进一步计算可以进一步实例化列表。这就是构建斑马之谜解决方案的原因:;是";对于问题";谜题有解决方案吗";,Prolog构建了一个实际描述解决方案的数据结构。
房屋列表Hs
是,永远不会是空的。它是在一开始就创建的
length(Hs, 5)
因此,它是一个包含五个最初未初始化的逻辑变量的列表,当它们被依次调用时,它们会被所有后续目标实例化,特别是被您提到的member/2
目标实例化。
要查看此示例,请尝试:
32 ?- L=[A,B,C], member(1, L).
L = [1, B, C] ;
L = [A, 1, C] ; % three solutions are found by Prolog
L = [A, B, 1]. % in turn, one after another
那些无法实现的调用(其中不可能实例化剩余的空闲逻辑变量(会导致特定的搜索分支失败。
一个例子:
33 ?- L=[1,2,C], member(3,L). % a check succeeds, while
L = [1, 2, 3], C = 3. % instantiating the `C` logvar
34 ?- L=[1,2,3], member(3,L). % a check succeeds
L = [1, 2, 3].
35 ?- L=[1,2,3], member(4,L). % a check fails
false.
当Hs
中的所有逻辑变量都被完全实例化时,最终只剩下成功的实例化,从而形成解决方案。