Recursion 序言递归

Recursion 序言递归,recursion,prolog,Recursion,Prolog,我正在制作一个函数,它将向我发送所有可能元素的列表。。在每次迭代中,它都会给我最后的答案。。但是在递归之后,我只得到最后一个答案。。我怎样才能让它把每一个答案都给我 多谢各位 问题是,我试图找到一个列表到其他列表中的所有可能分布。。代码 addIn(_,[],Result,Result). addIn(C,[Element|Rest],[F|R],Result):- member( Members , [F|R]), sumlist( Members, Sum), sum

我正在制作一个函数,它将向我发送所有可能元素的列表。。在每次迭代中,它都会给我最后的答案。。但是在递归之后,我只得到最后一个答案。。我怎样才能让它把每一个答案都给我

多谢各位

问题是,我试图找到一个列表到其他列表中的所有可能分布。。代码

addIn(_,[],Result,Result).
addIn(C,[Element|Rest],[F|R],Result):-
    member( Members , [F|R]),
    sumlist( Members, Sum),
    sumlist([Element],ElementLength),
    Cap is Sum + ElementLength,
       (Cap =< Ca,
    append([Element], Members,New)....
它只会进入一个while循环。。如果我换了衣服,会有更多的麻烦

   bp(NB,C,OL,A):-
            addIn(C,OL,[[],[],[]],A);
            bp(NB,C,_,A).
和而不是。。我得到一个错误:

错误:is/2:参数不是 充分实例化

谢谢你的帮助


非常感谢@hardmath

听起来您正在尝试编写自己版本的findall/3,可能仅限于基本目标的特例。在用户定义的Prolog谓词中进行一般性操作(构造给定目标的所有解决方案的列表)是不可能的,除非求助于

然而,许多有用的特殊情况可以在没有这些“把戏”的情况下实现。因此,了解什么谓词定义了“所有可能的元素”会很有帮助。[说明您使用的是哪种Prolog实现也可能会有所帮助,如果只是为了让响应包含指向该版本文档的链接。]

一个重要的特殊情况是潜在候选人的“宇宙”已经作为一个列表存在。在这种情况下,我们真正要求找到满足特定目标的“所有可能元素”的子列表

    findSublist([ ],_,[ ]).
    findSublist([H|T],Goal,[H|S]) :-
        Goal(H),
        !,
        findSublist(T,Goal,S).
    findSublist([_|T],Goal,S) :-
        findSublist(T,Goal,S).
许多序言允许您将谓词目标的名称作为“原子”传递,但如果您心中有一个特定的目标,您可以省去中间参数,只需将特定条件硬编码到类似实现的中间子句中

针对发布的代码添加:

我想我对你想做的事略知一二。这很难理解,因为你没有以正确的方式进行。谓词bp/4有一个递归子句,尝试使用AND或or语法将对addIn/4的调用与对bp/4本身的调用联系起来

显然,您希望以这种方式将bp/4包装在addIn/4周围,会导致addIn/4累积或迭代其解决方案。不会的。如果我们分析bp/4的参数发生了什么变化,可能会帮助您看到这一点

使用绑定到NB和C的简单整数、绑定到OL的整数列表以及作为未绑定“输出”答案的A调用形式参数bp(NB、C、OL、A)。请注意,从未对值NB执行任何操作,因为它不会传递给addIn/4,并且会原封不动地传递给对bp/4的递归调用

根据addIn/4和支持谓词insert/4使用的变量名,我猜NB的意思是“箱数”。首先,在test/0子句中设置NB=3,然后在调用addIn/4的第三个参数中“硬编码”三个空列表。无论您从bp/4得到什么样的答案,都来自addIn/4对其从bp/4传入的前两个参数C和OL所能做的。正如我们所注意到的,C是一个整数,OL是一个整数列表(至少在test/0调用bp/4时是这样)

因此,让我们试着说明一下addIn/4应该如何处理这些参数。从表面上看,addIn/4似乎是以一种合理的方式为自递归而构建的。它的第一个子句是一个简单的终止条件,即当第二个参数变为空列表时,统一第三个和第四个参数,并向其调用者提供“答案”

的第二条addIn/4似乎与该方法相协调。如前所述,它将第二个参数中的“head”元素从列表中删除,并尝试在第三个参数中找到可以插入元素的“bin”,同时将该bin的总和保持在C给出的“cap”下。如果一切顺利,最终OL中的所有数字都被分配到一个bin,所有bin的总数都在cap C下,然后答案A被传递回调用方。addIn/4的编写方式在基本的清晰性方面留下了很大的改进空间,但它可能正在做您需要它做的事情

这让我们回到您应该如何收集addIn/4产生的答案的问题。也许你很乐意一次打印一份。也许您想将addIn/4产生的所有解决方案收集到一个列表中。为了完成练习,我需要您澄清您真正想对中的答案做什么addIn/4

假设您希望将它们全部打印出来,然后停止,特殊情况是,如果传入的参数不允许解决方案,则不打印任何内容。那么你可能想要这种性质的东西:

newtest :-
    addIn(12,[7, 3, 5, 4, 6, 4, 5, 2], Answer),
    format("Answer = ~w\n",[Answer]),
    fail.
newtest.
这是一种让谓词addIn/4尝试所有可能的解决方案的标准方法,然后以newtest/0第二个子句的“失败”成功停止

(新增)关于编码的建议addIn/4:

  • 如果变量名是清晰的,它将使代码更具可读性和可维护性。我建议在计算分配给“bin”的项目总数时,使用Cap而不是C作为addIn/4和BinSum的第一个参数。同样,在使用成员的地方,Bin会更好。在的第三个参数addIn/4(在第二个子句的开头)中,您不需要显式的列表结构[F | R],因为您从不单独引用F部分或R部分。所以我会用垃圾箱
  • 您的一些谓词调用没有完成您无法轻松完成的任务。F
    newtest :-
        addIn(12,[7, 3, 5, 4, 6, 4, 5, 2], Answer),
        format("Answer = ~w\n",[Answer]),
        fail.
    newtest.