【问题标题】:Prolog: My newly created list becomes empty on exiting recursion?Prolog:我新创建的列表在退出递归时变为空?
【发布时间】:2015-05-12 15:10:46
【问题描述】:

我是 prolog 的新手,我正处于解决一个问题的边缘,但是当我尝试退出递归并将列表返回到初始函数时遇到问题。你能帮帮我吗?我整天都在为此苦苦挣扎。谢谢

当我建立列表时,最后会发生以下情况:

这是我的谓词:

depth_first(N, ReturnList) :-
   df_real(2:1, N, [2:1], ReturnList).

df_real(_:NextRankC, Size, Q, ReturnList) :- 
   genInt(Size, Row), 
   Column is NextRankC + 1,
   Rank = Row:Column,
   not(list_attack(Rank, Q)),
   add(Rank, Q, NewList),
   df_real(1:Column, Size, NewList, NewList).
% Recursive Case: Exit when list is full.
df_real(_, N, Q, Newlist) :- length(Q, Length),
   N = Length.

调用谓词: 深度优先(4,Q)。 注意:假设genInt/2add/3list_attack/2 工作正常,我的问题最终是它只是删除了我刚刚构建的所有元素并返回了一些变量,而不是 true,它必须返回列表。

我使用时更新

 df_real(_:NextRankC, Size, Q, NewList) :-
    ...
    df_real(1:Column, Size, NewList, NewList).

跟踪 - 添加失败,因为 NewList 现在是一个列表,而不是要添加到列表的变量。

【问题讨论】:

  • 您的谓词df_real(_:NextRankC, Size, Q, _) :- ... 有一个匿名变量_(未实例化),我假设您想在其中返回您的列表。让它,df_real(_:NextRankC, Size, Q, NewList) :- ... 代替。此外,为简洁起见,您的第一个谓词可以写成 depth_first(N, ReturnList) :- df_real(2:1, N, [2:1], ReturnList).
  • @lurker 没什么区别 :(
  • 什么不是?将NewList 作为df_real 的最后一个参数而不是_?我不明白它如何不能对结果产生影响。当你把它放在那里时,你会得到什么结果?即使它还不正确,它也必须产生一些的不同。从你的部分跟踪来看,它应该可以工作,或者至少让你更接近你想要的。
  • @lurker well 它是一样的 它返回 TRUE,当我跟踪它时,我得到相同的输出,当检查长度的条件返回 True 时,它​​会从创建的列表中弹出每个元素并返回变量,如在图片中:(
  • 为了清楚起见,请显示您运行的更新代码以及更新后的跟踪。如果您按照我的建议进行操作,那么跟踪将无法与您在问题陈述中显示的一样。您遇到的另一个问题是第一个参数也使用_(在_:NextRankC 术语中)。我不确定您打算如何处理该论点,但由于您将其设为匿名,因此它丢失了。也许没关系,因为无论如何你已经在第三个参数中传递了同样的东西。

标签: recursion prolog


【解决方案1】:

最终,代码的问题是您需要设置一个适当的模式来返回列表。 Prolog 中的一个常见模式是传入一个变量参数,该参数通过所有递归进行并最终在终端情况下实例化。该变量最初是在第一个子句中设置的。

depth_first(N, ReturnList) :-
    df_real(2:1, N, [2:1], ReturnList).

所以这里第一个查询是使用第 4 个参数作为返回答案列表的变量启动的,ReturnList。到目前为止,一切顺利。

df_real(_:NextRankC, Size, Q, ReturnList) :- 
    genInt(Size, Row), 
    Column is NextRankC + 1,
    Rank = Row:Column,
    not(list_attack(Rank, Q)),
    add(Rank, Q, NewList),
    df_real(1:Column, Size, NewList, NewList).

最初,您将_ 作为第四个参数,这是不正确的,因为您需要第四个参数作为可以返回答案的变量。现在将第 4 个参数设置为 ReturnList 很好,但是当前在此子句内部没有调用来实例化它。因此,您的跟踪显示 _XXXX 的值(未实例化)。问题在于最后一次通话:

    df_real(1:Column, Size, NewList, NewList).

出于某种原因,您将NewList 作为第三和第四个参数。您可能希望 ReturnList 作为第 4 个参数,以便通过递归进行并最终设置:

    df_real(1:Column, Size, NewList, ReturnList).

最后,终端(或基本)案例:

% Recursive Case: Exit when list is full.
df_real(_, N, Q, Newlist) :-
    length(Q, Length),
    N = Length.

NewList 作为这里的第四个参数什么都不做。这是一个单例变量,不会填充任何内容。因此,在跟踪中,它将显示为_XXXX,而您在ReturnList 中将没有答案。当Q 列表达到长度N 时,该子句表明您已完成。我假设,在这一点上,Q 是你想要的答案。所以你只需要在 Prolog 中这样说:

% Recursive Case: When list is full, it's the answer
df_real(_, N, Q, Q) :-
    length(Q, N).

您还可以通过简化第一个参数来稍微整理一下。这是X:Y 形式的术语,而您从不使用X,那么为什么要随身携带呢?

depth_first(N, ReturnList) :-
    df_real(1, N, [2:1], ReturnList).

df_real(_:NextRankC, Size, Q, ReturnList) :- 
    genInt(Size, Row), 
    Column is NextRankC + 1,
    Rank = Row:Column,
    \+ list_attack(Rank, Q),   % Note use of ISO negation predicate, \+
    add(Rank, Q, NewList),
    df_real(Column, Size, NewList, ReturnList).

% Recursive Case: When list is full, it's the answer
df_real(_, N, Q, Q) :-
    length(Q, N).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-22
    • 2012-10-04
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多