Prolog - 从基本情况返回值

发布于 2024-09-29 00:51:21 字数 1417 浏览 3 评论 0原文

好的,事情是这样的:

  • 我有两堆衬衫,
  • 我想从每堆中随机取出一件衬衫并将它们放入新的一堆中
  • ,然后将新的一堆拿出来

这是代码:

mix([],[],_).
mix(P1,P2, Pile):-
    takeshirt(P1,1,Taken1,Rem1), takeshirt(P2,1,Taken2,Rem2), #Take one
    append(Pile,Taken1,New),     append(New,Taken2,NewPile),  #Put both of them
    mix(Remain1,Remain2,NewPile).

这就是结果的样子:

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [] .

我希望它看起来像:

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [b, d, a, c] .

或者无论结果是什么。我通过图形调试器进行检查,发现当最终调用 mix 时,绑定为:

P1 = Taken1 = [b]
P2 = Taken2 = [c]
Pile           = [a, d]
Rem1 = Rem2 = []
New         = [a, d, b]
NewPile     = [a, d, b, c] #<--- Interresting  

因此,当最终调用:

mix([],[],_). 

发生时,所需的值位于 NewPile 中。在此之后,它就像纸牌屋一样倒塌了。

所以问题是:

mix([],[],_).

我想从基本情况返回 _ 值,这条规则mix实际上是在一个更高的实例中使用的,我在其中发送了两堆并且把新的一堆拿出来。

更新:
为了澄清有关 takeshirt 规则的一些评论,这里是:

takeshirt(_,0,[],_).
takeshirt(List,Number,[Element|Taken],Remain) :- N > 0,
    length(List,Len),
    Index is random(Len) + 1,
    removeshirt_at(Element,List,Index,Remain),
    Number1 is Number - 1,
    takeshirt(Remain,Number1,Taken,Remain). 

Ok, here's the deal:

  • I've got two piles of shirts
  • I want to take a random shirt from each pile and put them in a new pile
  • Then get the new pile out

And here is the code:

mix([],[],_).
mix(P1,P2, Pile):-
    takeshirt(P1,1,Taken1,Rem1), takeshirt(P2,1,Taken2,Rem2), #Take one
    append(Pile,Taken1,New),     append(New,Taken2,NewPile),  #Put both of them
    mix(Remain1,Remain2,NewPile).

This is what the result look like:

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [] .

I want it to look like:

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [b, d, a, c] .

Or whatever the result is. I checked via the graphical debugger and found out that when the final call to mix happens, the bindings are:

P1 = Taken1 = [b]
P2 = Taken2 = [c]
Pile           = [a, d]
Rem1 = Rem2 = []
New         = [a, d, b]
NewPile     = [a, d, b, c] #<--- Interresting  

So the wanted value is in NewPile when the final call to:

mix([],[],_). 

happens. After this is it collapses like a house of cards.

So the question is:

mix([],[],_).

I'd like to return the _ value from the base case, this rule mix is actually used from a higher instance where I send in two piles and get the new pile out.

Update:
To clarify some comments about the takeshirt rule, here it is:

takeshirt(_,0,[],_).
takeshirt(List,Number,[Element|Taken],Remain) :- N > 0,
    length(List,Len),
    Index is random(Len) + 1,
    removeshirt_at(Element,List,Index,Remain),
    Number1 is Number - 1,
    takeshirt(Remain,Number1,Taken,Remain). 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我做我的改变 2024-10-06 00:51:21

考虑对您的代码进行以下修改:

mix([], [], []) :- !.
mix(P1, P2, Pile) :-
    takeshirt(P1, 1, Taken1, Rem1), 
    takeshirt(P2, 1, Taken2, Rem2),
    append(Taken1, Taken2, Pile0),
    mix(Rem1, Rem2, Pile1),
    append(Pile0, Pile1, Pile).

看来您需要积累“衬衫”(作为列表原子)。在这里,我们递归地将它们附加到 mix/3 (Pile) 的第三个参数上,直到两个输入列表都为空时命中基本情况(第一个子句)列表(请注意,此处需要剪切 !,因为第二个子句的绑定模式与第一个子句匹配,因此我们要排除它)。第二个子句的行为(每一步从每个输入列表中获取一件衬衫)要求它们一开始就必须具有相同的长度。

为了测试这一点,我使用了以下 takeshirt/4 定义:

takeshirt(Ps, _, [P], Rem) :-
    select(P, Ps, Rem).

请注意,此处的第二个参数未使用,因为 select/3 用于获取单个元素(一件衬衫),并返回余数。 select 之后缺少剪切 (!) 允许此谓词回溯从列表中选择所有其他元素(衬衫)。如果我们现在使用此定义执行示例查询,我们可以获得:

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [a, c, b, d] ;
NewPile = [a, d, b, c] ;
NewPile = [b, c, a, d] ;
NewPile = [b, d, a, c] ;
false.

...我们可以看到 mix/3 通过从第一堆中取出一件衬衫来枚举回溯时所有可能的“堆”(第一个输入列表),然后是第二堆(第二个输入列表)中的一件衬衫,依此类推,直到两个输入列表都为空。如果您对 takeshirt/4 的定义没有留下选择点(不可回溯),那么您只能得到一种解决方案(如果有)。

Consider the following modifications to your code:

mix([], [], []) :- !.
mix(P1, P2, Pile) :-
    takeshirt(P1, 1, Taken1, Rem1), 
    takeshirt(P2, 1, Taken2, Rem2),
    append(Taken1, Taken2, Pile0),
    mix(Rem1, Rem2, Pile1),
    append(Pile0, Pile1, Pile).

It seems you need to accumulate the 'shirts' (as list atoms). Here, we are recursively appending them onto the third argument of mix/3 (Pile), until the base case (the first clause) is hit when both input lists are empty lists (note that the cut ! is necessary here as the binding pattern for the second clause matches the first, so we want to exclude it). The behaviour of the second clause, which takes a shirt from each input list for every step, requires that they must have been of equal length to start with.

To test this, I used the following definition of takeshirt/4:

takeshirt(Ps, _, [P], Rem) :-
    select(P, Ps, Rem).

Note that the second argument here is unused, as select/3 is being used to take a single element (a shirt) from the list, and return the remainder. The absence of a cut (!) after the select allows this predicate to backtrack in selecting all other elements (shirts) from the list. If we now execute your example query with this definition, we can get:

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [a, c, b, d] ;
NewPile = [a, d, b, c] ;
NewPile = [b, c, a, d] ;
NewPile = [b, d, a, c] ;
false.

...we can see that mix/3 enumerates all possible 'piles' on backtracking by taking a shirt from the first pile (first input list), then a shirt from the second pile (second input list), and so on, until both input lists are empty. If your definition of takeshirt/4 doesn't leave choice-points, (is non-backtracking), then you could only get one solution, if any.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文