我有这段代码可以将输入列表分成两半。好像还可以
halve(List,A,B) :- halve(List,List,A,B), !.
halve(B,[],[],B).
halve(B,[_],[],B).
halve([H|T],[_,_|T2],[H|A],B) :-halve(T,T2,A,B).
好的,所以我尝试对其进行解码。开头很清楚:
“减半获取列表和2个逻辑变量”是这样的:
halve(List,A,B)
(1)然后继续这一部分:
:- halve(List,List,A,B).
这意味着,我要从第一个创建新的两个列表(列表,列表),或者是什么?确切地代表“:-”的是什么?我猜新的列表= A和B将减半,对吧?
(2)第二,请,我不太明白这两行:
halve(B,[],[],B).
halve(B,[_],[],B).
也许您可以在一些例子中解释一下?
(3)好吧,希望您对(1)和(2)做出解释后,我会自己做最后一部分...
halve([H|T],[_,_|T2],[H|A],B) :- halve(T,T2,A,B).
非常感谢您对我的帮助。
好的,我们的第一个问题已经有了解决方案。长话短说,它是这样的:
halve([1,2,3,4,5],[1,2],[3,4,5]).
->true
如果您注意到它将列表分成两半,但是如果列表中元素的数量为奇数,则后半部分为较大的元素。
现在,我想要获得的是第一个更大的。
所以我在想这个:
我要达到这个目标:
Halves_div([1,2,3],A,B).
A=[1,2],
B=[3].
假设我的输入是列表:[1,2,3]。因此,我将从分割列表的头部和尾部开始:
[H|T]
,然后将H
与新的空列表合并-我的第一半(A
)。之后,我有A = [1],B = []和Input = [2,3]。
对于合并,我有:
merge([],List,List).
merge([H|T],List,[H|New]) :- merge(T,List,New).
还有一件事-我需要检查第一半是否已经> =第二半,对吗?
所以这是我的主意,我唯一希望您提供帮助的就是写在序言中。我有点困惑如何将其放在一起。
谢谢!
看来我的解决方案想法太复杂了,我发现更好的东西!
最佳答案
首先,Prolog子句如下所示:
Head :- Body
您可以将其读为“
Head
(如果Body
”)或“ Body
暗示Head
”。请注意,有时您只有
Head
那是因为Head总是
true
。在这种情况下,我们不称Head
子句,而是称其为事实。所以在这里,我们有:
halve(List,A,B) :- halve(List,List,A,B).
这意味着,如果
halve(List, A, B)
为true,则halve(List, List, A, B)
为true。具体来说,这只是将halve/3
的工作委托给halve/4
的一种方法,即所谓的工作者谓词。为什么我们需要一个工人谓词?好吧,因为在这里我们想使用另一个变量来计算
A
和B
项。但是我们无法使用halve/3
进行操作,因为halve/3
的3个参数点已由输入列表List
,结果的前半部分,A
和结果的下半部分占用, B
。关于
List, List
事情,这只是一种说法,就像使用任何编程语言一样,我们用相同的第一和第二个参数调用halve/4
。然后有趣的东西开始了。 Prolog将尝试证明
halve/4
对于某些给定参数是正确的。假设以这种方式说明我们称为halve/3
的执行:?- halve([1, 2], A, B).
然后,如果您按照我之前提到的内容进行操作,那么Prolog现在将通过使用以下参数证明
halve/3
正确,从而尝试证明halve/4
正确。为此,Prolog有3种选择。首选是以下子句:
halve(B,[],[],B).
显然,那是行不通的。因为当Prolog尝试通过统一使调用方的第二个参数适合被调用方的第二个参数时,它将失败。因为
halve([1, 2], [1, 2], A, B).
无法与[1, 2]
统一。仅剩两个选择,下一个是:
halve(B,[_],[],B).
同样,Prolog无法统一
[]
和[1, 2]
,因为[_]
只是一个变量(如果遇到麻烦,请参见my post有关匿名变量_
的信息)。因此,Prolog必须为您提出的问题找到解决方案的唯一机会是最后一个子句,即:
halve([H|T],[_,_|T2],[H|A],B) :- halve(T,T2,A,B).
在这里,Prolog将找到一种统一事物的方法,让我们看看哪种方法:
我们必须将
_
与[1, 2]
统一起来。这意味着[H|T]
和H = 1.
我们必须将
T = [2].
与[1, 2]
统一起来。这表示[_,_|T2]
现在我们开始用下一个统一的结果建立结果,即
T2 = [].
(我对第二个A = [H|A']
进行了预填,因为变量是局部作用域的,并且它们是不同的)。在这里,我们告诉我们从子句的主体中计算出结果时,将在其中添加A
。这里的H
是H
,因此我们已经知道1
的第一个元素将是A
。好吧好,统一成功了,太好了!我们可以继续该条款的正文。它只是使用这些值(如上计算)以递归方式调用
1
:halve([2], [], A, B).
在这里,我们从头再来。尽管这次情况很快,因为Prolog的首选将非常适合:
halve(B,[],[],B).
可以统一为
halve([2], [], A, B).
具有以下值:
halve/4
和A = []
。因此,这是一个好步骤,我们现在到达了递归的“基本情况”。现在,我们只需要从下到上建立结果。还记得上面几步递归调用谓词
B = [2]
吗?我们已经说过,halve/4
的第一个元素是A
。现在我们知道尾巴是1
,所以我们可以声明[]
。我们没有对A = [1]
进行特别说明,因此B
保持不变。现在,我详细介绍了执行过程,您可能想知道,为什么这样做有效?好吧,如果您注意的话,您会注意到
B = [2]
的第二个参数的执行速度是第一个参数的两倍。 halve/4
与[H|T]
。这意味着当我们使用第二个参数将列表结尾时,第一个仍然在列表的中间。这样,我们可以将事物分为两部分。希望我能帮助您了解这里工作中的一些细微问题。