现在,我很难尝试定义一个谓词ascending/1
,它接受一个列表列表,并确定列表是否按照增加大小的列表列表进行排序。我创建了一个帮助谓词smaller/2
,并接受了2个列表,例如A和B',如果A的长度小于或等于B,则会成功,否则将失败。我的问题是,如果假设smaller/2
正确实现,我如何递归调用谓词ascending/1
中的smaller/2
?我是prolog的新手,所以语法让我感到困惑。到目前为止,我有:
%empty list%
ascending([]).
ascending([Z]) :- smaller ([_|Z]), [_,_|Z]).
我试图抓住列表列表的头部并将其与列表列表的第二个头部进行比较。 我也不想只使用我的帮助器谓词。
答案 0 :(得分:2)
所以,这是我的答案 - a related question同时出现了。
在回答原始问题之前,我将查看升序的整数列表。原因是:在列表及其元素之间进行区分只是更简单。
避免使用命令,因为(纯)Prolog谓词什么都不做。或者充其量他们描述关系。但他们没有排序或添加或比较。在我们的情况下,ascending/1
可能是一个理想的名称,sorted/1
不太理想,因为它有点暗示有人会对事物进行排序。因此,周围仍然存在一个微小的imp(强制性实体)。
这通常有助于澄清你的意思。永远记住:现在,你的思想很新鲜,所以要努力添加有意义的测试用例。稍后你会变得疲倦而不那么专心,但让我向你保证:你的Prolog系统永远不会累。因此,您可以将这些测试用例放在文件的末尾:
?- ascending([1,2]).
?- ascending([1,1,2]).
?- \+ ascending([2,1]).
(微不足道的)第一次尝试可能是:
ascending(_).
这个定义永远成功!显然太笼统了。那么我们如何专注呢?添加单个目标将不起作用。但由于它应该是一个列表 - 我们可以从列表的定义开始。
ascending([]).
ascending([_E|Es]) :-
ascending(Es).
现在,这仍然是一般的,我们想要一个具有某些属性的整数列表。所以我们再次需要专门化这个定义。我们想要的是Es = [A,B,C]
目标A #=< B, B #=< C
成立。
:- use_module(library(clpfd)).
ascending([]).
ascending([E|Es]) :-
E #=< F,
ascending(Es).
您是否看到有关F
单身人士的警告? Prolog讨厌这些变量,它们经常是拼写错误。从某种意义上讲,Prolog是对的。我们应该将F
与其他内容联系起来。它应该是Es
中的下一个元素。
ascending([]).
ascending([E|Es]) :-
lesseq_than_first(E, Es),
ascending(Es).
lesseq_than_first(_, []).
lesseq_than_first(E, [F|_]) :-
E #=< F.
我们可以“优化”这个定义。但是这种形式更好地揭示了它的含义:它是一个列表,元素是相互关联的。
升序整数列表非常多。但是,列表升序的事实是多么重要,下降列表几乎不能具有相同的定义?如果有太多的名字填满我们超载的头脑,这不是浪费我们的宝贵关注吗?
我们基本上有一系列与(#=<)/2
互连的价值观,可能是任何其他关系。因此,我们可以说ascending([1,2,3])
而不是chain(#=<, [1,2,3])
。 (顺便说一句:这个名字好吗?或者你有更好的名字?)
chain(R_2, []).
chain(R_2, [E|Es]) :-
rel_to_first(R_2, E, Es),
chain(R_2, Es).
rel_to_first(_R_2, _E, []).
rel_to_first(R_2, E, [F|_]) :-
call(R_2, E, F).
通过这个一般定义,我们现在可以回到原始谓词:smaller/2
不是理想的名称。也许shorter_than/2
?
shorter_than([], _).
shorter_than([_|Es], [_|Fs]) :-
shorter_than(Es, Fs).
sorted(Ess) :-
chain(shorter_than, Ess).
写完这篇文章之后,我意识到我忘了说明另一个好建议:和顶级玩家一起玩吧!但这不符合这个答案......