如何在Prolog中获得not效果

How to get the not effect in Prolog

我正在尝试创建一个递归调用自身的规则,并找到遍历有向图的所有可能路径。我正在使用 findall() 来这样做。函数是 traverse(Start,End).

我有:

traverse(Start,End,[li]) :-
   node(Start,End),
   append(End,Li).

traverse(Start,End,[Li]) :-
   node(Start,Z),
   traverse(Z,End),
   append(Start,Li).

/*here I would like to check that Z is not a member of Li before
  I call traverse(Z,End), I know I can check that it is a member
  using member(Z,Li) but how to I check it is not a member in 
  prolog*/

findalltraverses(Start,End,[list]) :-
   findall(_,traverse(Start,End).

开始之前:这种语言称为 prolog。

您的代码在不同级别有多个 mistakes/errors。这是它们的(不完整)列表:

  • findall 需要右括号。
  • findall需要3个参数。第一个位置是您感兴趣的内容,第二个是如何获取数据(哪个调用),第三个是您的答案的容器。您对容器感兴趣,所以 findalltraverses 应该将其作为属性。
  • 节点和边是有区别的。一条边连接两个节点。
  • 变量以大写字母或下划线开头。
  • 如果变量 L 与列表统一,您不必像 [L] 那样声明它,因为例如 L=[1,2,3] [L] 会变成 [[1,2,3]] 这是一个包含 123.
  • 列表的列表
  • 递归调用经常有两种情况:结束设置和递归调用设置。你这个概念是对的。
  • append 有 3 个参数:lists L1L2L3,其中 L1 L2 附加的是 L3.
  • 您的谓词 traverse/3 有 3 个属性。没有为 2 个属性定义谓词 traverse/2
  • 您不能覆盖变量。一旦设置了变量的值,就不能再更改它。例如:如果你有一个数字 N 并且想要增加它,你需要使用不同的变量来保存结果:N1 is N+1.
  • 将单个元素 E 添加到列表 L 作为头元素(意思是将其放在第一个位置)可以通过头尾写法来完成:[E|L]。对于 E=1L=[2,3][E|L] 变为 [1,2,3]
  • 为了避免无限循环,您需要跟踪您已经访问过的节点。但是,如果您对从 StartEnd 的路径感兴趣,则您需要以某种方式转发该路径。不可能仅将列表与已访问节点一起使用,因为在通过递归返回时不会保留此知识。所以你的 traverse 谓词应该有 4 个属性。
  • “不能”可以用\+表示,相当于“无法证明”

好的,这是截取的工作代码。递归结束部分有点不同,因为它不检查是否存在从 StartEnd 的边,而是询问 StartEnd 是否相同。如果是这样,则生成的路径仅包含此节点。这很重要,因为在代码中截断的路径将在通过递归(返回时构建([Start|Path]),而包含访问节点的列表在时增长进入 递归 ([Start|Visited]).

edge(a,b).
edge(b,c).
edge(c,d).
edge(a,d).

traverse(End,End,_,[End]).
traverse(Start,End,Visited,[Start|Path]) :-
    edge(Start,Tmp),
    \+ member(Tmp,Visited),
    traverse(Tmp,End,[Start|Visited],Path).

findalltraverses(Start,End,Out):-
   findall(List,traverse(Start,End,[],List),Out).

我们来测试一下!

?- findalltraverses(a,d,Out).
Out = [[a, b, c, d], [a, d]].

看起来不错。