【问题标题】:prolog - tail recursion issueprolog - 尾递归问题
【发布时间】:2014-03-17 23:57:01
【问题描述】:

我是 prolog 的新手,我正在尝试创建谓词,但遇到了一些麻烦。

我有一个通过火车连接的城市列表。它们通过我的 links/2 子句连接。

links(toronto, ajax).
links(toronto, markham).
links(toronto, brampton).
links(brampton, markham).
links(markham, ajax).
links(brampton, mississauga).
links(mississauga, toronto).
links(mississuaga, oakville).
links(oakville, st.catharines).
links(oakville, hamilton).
links(hamilton, st.catharines).

我正在编写一个名为 addnewcities 的谓词,它将获取一个城市列表,然后返回一个包含原始列表的新列表,以及与原始列表中的每个城市直接相连的所有城市。

这是链接的(粗略)视觉表示。

如果我的输入列表是[toronto],我希望我的输出是(顺序无关)[ajax,markham,brampton,mississauga,toronto]

如果输入是[oakville,hamilton],我希望输出是[mississauga,st.catharines,oakville,hamilton]

到目前为止,这是我的谓词。

addnewcities([],_).
addnewcities([CitiesH|Tail],Ans):- directer(CitiesH,Ans2),  merger(Ans2,[CitiesH],Ans), addnewcities(Tail,Ans).

directer/2 获取一个城市并在第二个参数中保存一个包含所有直连城市的列表。

merger/3 只是合并两个列表,确保最终列表中没有重复项。

当我的输入是一个包含一个元素的列表时,即[toronto] 它可以工作! 但是当我有一个包含多个元素 [toronto,ajax] 的列表时,它每次都说“假”。

我很确定我的问题是,当它第二次递归时,merge 就是它的错误。我只是不知道如何解决这个问题,以便我的列表可以不断更新,而不是检查真假。

感谢任何帮助!

【问题讨论】:

  • merge/3 将在递归调用 addcities(Tail,Ans) 上失败,因为在该递归调用中您已经实例化了 Ans。对merge(Ans2,[CitiesH],Ans) 的调用尝试将Ans2[CitiesH] 合并,无法匹配Ans 中已经实例化的结果,因此失败。递归调用addcities(Tail,Ans) 需要一个未绑定变量作为第二个参数。然后你需要弄清楚如何处理那个未绑定的变量。
  • 我现在明白它失败的原因和位置了。但我只是不知道如何解决它。我是否应该创建一个不同的谓词,然后将该未绑定的变量发送到 is 并在那里完成工作?
  • 仔细想想你的递归子句在逻辑上的含义。 addcities([CitiesH|Tail],Ans) :- 表示 Ans 是与列表中的城市直接相连的所有城市的列表 [CitiesH|Tail] if... 并用您可以翻译成 Prolog 的文字表达其余部分。

标签: list recursion prolog tail-recursion


【解决方案1】:

此查询使用库支持来解决问题:

addcities(Cs, L) :-
  setof(D, C^(member(C,Cs), (C=D;link(C,D);link(D,C))), L).

【讨论】:

  • 这会产生我需要的确切结果!无论如何,您可以向我解释插入符号的作用吗?我一直在寻找有关它的文档,但找不到任何东西。谢谢!
  • 简短解释:插入符号告诉 Prolog 绑定变量。要了解这意味着什么: findall/3 不绑定任何变量。请参阅bagof/3 的 SWI-Prolog 文档
【解决方案2】:

这应该可以满足您的需求:

addcities(A,B):-
    addcitiesaux(A,[],B).

addcitiesaux([],X,X).

addcitiesaux([X|Xs],L,R):-
    link(X,A),
    \+ member(A,L),
    !,
    addcitiesaux([X|Xs],[A|L],R).

addcitiesaux([X|Xs],L,R):-
    link(A,X),
    \+ member(A,L),
    !,
    addcitiesaux([X|Xs],[A|L],R).

 addcitiesaux([X|Xs],L,R):-
    addcitiesaux(Xs,[X|L],R).

【讨论】:

  • 这个答案很接近,但结果列表并不总是包含原始列表中的城市。
  • 对不起,我没有读到您应该包含原始列表中的城市,您可以通过在最后一个谓词中包含 X 来添加它们。您可以看到已编辑的答案。
猜你喜欢
  • 1970-01-01
  • 2011-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-09
  • 1970-01-01
  • 2011-05-28
  • 1970-01-01
相关资源
最近更新 更多