我必须编写一个带有List的谓词,如果列表在列表中的任何位置包含元素“a,b,c”,则必须成功,否则它将失败。我很遗憾在哪里开始(不是寻找解决方案,只是提示正确的方向)。
答案 0 :(得分:4)
几乎总是,当Prolog任务以相当命令式方式制定时,解决方案将相对有限。这意味着我们通常只能在几种模式和方向上使用它,而其他模式甚至可能产生错误的结果。
因此,我建议使用更多声明性措辞。
你说:
如果列表包含元素“a,b,c”,那么获取列表成功的谓词列表,否则失败。
这是一种相当程序的方式来看待这个。请注意,在Prolog中,任何参数也可以是逻辑变量,因此甚至可能没有“take”列表。相反,我们希望谓词在这些情况下生成这样的列表!
注意你的措辞!通常,当您能够以声明方式表达任务时,优雅而通用的Prolog解决方案将是直截了当的,并且通常非常自然地遵循任务描述。
首先,让我们关注持有什么。没有必要表达不包含的内容,因为在这种情况下,谓词无论如何都不会成功。
我们想要描述?
基本上,我们希望描述形式的{/ 1}}列表。
已经有一些答案,有各种缺点。
纯方式使用来自Indexing dif/2的元谓词[...,a,b,c,...]
:
abc([X,Y,Z|Vs]) :- if_((X=a,Y=b,Z=c), true, abc([Y,Z|Vs])).
这适用于所有方向。首先,让我们尝试最常规的查询,其中单个参数是一个新的变量:
?- abc(Vs). Vs = [a, b, c|_5032] ; Vs = [a, b, a, b, c|_5144] ; Vs = [a, b, a, b, a, b, c|_5286] .
因此,我们可以生成解决方案,这是关系的一个非常好的属性!
谓词是单调,因此迭代加深可以公平地枚举答案:
?- length(Vs, _), abc(Vs). Vs = [a, b, c] ; Vs = [a, b, c, _11600] ; Vs = [a, a, b, c] ; Vs = [_11982, a, b, c], dif(_11982, a) ; Vs = [a, b, c, _11600, _11606] .
由此可见,无解决方案少于3个元素。在这种情况下,这是非常明显的。在其他情况下,从任务描述中可能不太明显这样的结果。
如果谓词充分实例化,则谓词确定性。
例如:
?- abc([a,b,c]). true. ?- abc([z,a,b,c]). true. ?- abc([a,b,c,z]). true.
请注意,在这些情况下,没有选择点仍然存在!
答案 1 :(得分:2)
以下是您可以采取的三种方法,按灵活性大致按升序排列:
首先,是使用谓词nth0/3来查找列表中a,b和c的位置,然后检查<的位置。 b的位置< c的位置对于列表中a,b和c的多个实例(例如[c,b,a,b,c,a]),nth0将依次找到每个匹配元素的位置,这样如果有三个位置适合于标准(即使它们不是第一个位置),谓词也会成功。
提示1.1:nth0的语法,用于查找。
的位置
nth0(PositionA,[c,b,a,b,c,a],a)
提示1.2:语法小于(完整性)
PositionA < PositionB
部分解决方案1:使用nth0检查a,b和c在列表[c,b,a,b,c,a]中以某种顺序出现的一系列命令(汇总谓词留给你)
nth0(PositionA,[c,b,a,b,c,a],a),
nth0(PositionB,[c,b,a,b,c,a],b),
nth0(PositionC,[c,b,a,b,c,a],c),
PositionA < PositionB,
PositionB < PositionC.
第二种方法使用列表模式匹配 - 我们观察到,当下到列表时,我们必须遇到a,然后是b,然后是c。为此,我们可以构造三个查找a,b和c的谓词,然后在适当的位置传递列表的其余部分。我们必须构造这些谓词,以便在看到目标之前忽略其他元素。
提示2.1:谓词的头部,其中a是列表的第一个元素
find_a([a|Rest]) :-
提示2.2:谓词的头部,其中任何内容都是列表的第一个元素
find_a([_|Rest]) :-
提示2.3:当我们找到a时,我们开始寻找b
find_a([a|Rest]) :-
find_b(Rest).
提示2.4:当我们找不到时,我们一直在寻找
find_a([_|Rest]) :-
find_a(Rest).
提示2.5:订单很重要(实物)
如果我们先将
find_a([a|Rest])
置于知识库中,那么Prolog将始终首先尝试统一它,因此我们将匹配我们找到的第一个。如果我们把它放在第二位,这仍然有用,但是有很多额外的回溯,我们会发现每个都是相反的顺序。
提示2.6:不要忘记基本情况!
请记住,即使你找到c后你不需要做任何事情,你仍然需要创建一个事实,说明它是列表的头部:
find_c([c|_]).
第三种方法本质上是第二种方法的通用版本 - 而不是创建谓词来查找a,b和c,而是创建一个按顺序查找元素列表的谓词。
提示3.1:您的谓词应该采用两个列表并比较每个
的头部
compare([A|Targets],[B|Checks]) :-
提示3.2:如果相同的变量名出现在多个位置,则它必须具有相同的谓词值才能匹配
compare([A|Targets],[A|Checks]) :- % succeeds when the same element is at the head of each list
提示3.3:如果匹配,请继续按两个列表
compare(Targets,Checks).
提示3.4:如果它们不匹配,只需查看检查清单
compare([A|Targets],Checks).
提示3.5:永远不要忘记基本情况(当没有更多目标时)
compare([],_).
提示3.6:和以前一样,订购仍然很重要
之前的知识库中
compare([A|Targets],[A|Checks]) :- ...
应位于compare(Targets,[_|Checks]) :- ...
解决方案3:
compare([],_).
compare([A|Targets],[A|Checks]) :-
compare(Targets,Checks).
compare(Targets,[_|Checks]) :-
compare(Targets,Checks).
希望这有帮助!
答案 2 :(得分:1)
要按顺序查找列表中的字母a,b,c
,应该从@lurker的评论开始,该评论显示[X, Y, Z | T]
。
has_abc([a,b,c|T]).
由于我使用的是SWI-Prolog而不愿意收到警告
警告:somecode.pl: 单例变量:[T]
我会通过将T
更改为_
has_abc([a,b,c|_]).
然后运行一些简单的测试
?- has_abc([a,b,c]).
true.
?- has_abc([a,b,c,z]).
true.
?- has_abc([z,a,b,c]).
false.
正如您所看到的,谓词has_abc
可以在列表的开头找到a,b,c
,但不能在其他地方找到。{/ p>
在Prolog中,可以使用[H|T]
deconstruct_list([Head | Tail]): - 写('列表头:'),写(头),nl, deconstruct_list(尾部)。
和一些示范案例
?- deconstruct_list([]).
false.
?- deconstruct_list([a]).
Head of list: a
false.
?- deconstruct_list([a,b]).
Head of list: a
Head of list: b
false.
?- deconstruct_list([a,b,c]).
Head of list: a
Head of list: b
Head of list: c
false.
现在结合前两个谓词来查找a,b,c
并解构列表给我们
has_abc([a,b,c | _])。
has_abc([_ | T]): - has_abc(T)。
和一些测试用例
?- has_abc([]).
false.
?- has_abc([a]).
false.
?- has_abc([a,b]).
false.
?- has_abc([a,b,c]).
true .
?- has_abc([z,a,b,c]).
true .
?- has_abc([a,b,c,z]).
true .
?- has_abc([z,a,b,c,z]).
true .
几乎就在那里。有一个小问题,因为对于true
答案,我们必须按Enter
退出,这表示我们有一个选择点。
解决这个问题的一种方法是使用cut
(!)表示一旦我们有一个答案停止寻找更多答案。
has_abc([a,b,c | _]): - !.
has_abc([_ | T]): - has_abc(T)。
和一些测试用例
?- has_abc([]).
false.
?- has_abc([a]).
false.
?- has_abc([a,b]).
false.
?- has_abc([a,b,c]).
true.
?- has_abc([z,a,b,c]).
true.
?- has_abc([a,b,c,z]).
true.
?- has_abc([z,a,b,c,z]).
true.
?- has_abc([d]).
false.
?- has_abc([d,e]).
false.
?- has_abc([d,e,f]).
false.
?- has_abc([d,e,f,g]).
false.
请注意,在运行测试用例时,无需按Enter
即可结束查询。
通过mat
查看答案