【问题标题】:Prolog returning true/false instead of variableProlog 返回真/假而不是变量
【发布时间】:2015-06-01 19:40:05
【问题描述】:

我正在编写 Prolog 中非常简单的反向列表示例。

append(A, [], [A]).
append(A, B, [A|B]).

reverse([], ReversedList).
reverse([A,B], ReversedList) :-
  reverse(B, TemporaryList),
  append(A, TemporaryList, ReversedList).

append 工作正常。但是,当我调用 reverse 时,解释器不会响应 append 之类的变量,而是只写 true 或 false。

这是日志:

1 ?- consult('capitolo2'.pl). % file containing the code
2 ?- append(a, [b,c,d], L).
L = [a,b,c,d]. % ok, this works
3 ?- reverse([a,b,c], L).
false. % what? why that's not L = something?

平台是 Windows 上的 SWI-Prolog 7.2

【问题讨论】:

  • 这是append 的一个相当不标准的定义,通常append 被定义为在列表上工作,例如append([a,b,c], [x,y,z], L) ==> L = [a,b,c,x,y,z], stackoverflow.com/questions/11539203/…
  • 看来这不是问题。如果我将 append 重命名为 my_append 是一样的
  • 你也需要重启 Prolog 系统。此外还有[A,B],它可能应该读作[A|B]等等......
  • 只有当第一个参数是空列表 ([]) 或两个元素列表 ([A, B]) 时,您的 reverse 规则才会成功。它将失败所有其他情况,因为它们不匹配。
  • 你为什么要实现像append/3这样的标准谓词?如果你有充分的理由去做,为什么一旦遇到问题你不去查一下?

标签: prolog


【解决方案1】:

append/3

单元测试了吗?它工作正常吗?您的 append/3 实现不正确。第一个子句

第一个子句:

append( A , [] , [A]   ). 

简单地从它的第一个参数(不管它可能是什么)创建一个长度为 1 的列表。鉴于此,如果你说:

append( [1,2,3] , [] , X ) .

你会回来的:

X = [ [1,2,3] ]

长度为 1 的列表,其中包含的唯一项目是原始的第一个参数。第二个子句同样不正确:

append( A , B , [A|B] ).

将第一个参数(无论它可能是什么,以及全部)作为该列表的开头。鉴于此,如果您说的是:

append( [1,2,3] , [a,b,c] , X ) .

你会回来的:

X = [ [1,2,3] , a , b , c ] .

长度为 4 的列表,第一项是原始的第一个参数。

Prolog 是一种描述性语言:您描述解决方案并让引擎解决问题。 append/3 断言列表(append/3 的第三个参数表示第一个参数和第二个参数的连接。

这里是append/3 的实现,为清楚起见进行了简化:

append( []      , RL , RL ) .  % The concatenation of an empty left-hand list and a right hand list is the right hand list.
append( [LH|LT] , RL , CL ) :- % The concatenation of a non-empty left-hand list and a right-hand list is true IF:
  CL = [LH|CT] ,               % - The left-hand head and the concatenation head are the same, AND
  append( LT , RL , CT )       % - recursively, the concatenated tail represents the conconcatenation of the left-hand tail and the right-hand list.
  .                            % Easy!

当您从左侧列表中弹出项目时,它最终会分解为终止的特殊情况。这可以简化为经典实现:

append( []      , RL , RL      ) .
append( [LH|LT] , RL , [LH|CT] ) :- append( LT , RL , CT ) .

reverse/3

同样,您的 reverse/3 实现不正确。你的第一个子句:

reverse([], ReversedList).

几乎说几乎任何东西都是空列表的反面。由于从未引用您的 ReversedList 变量,因此您的 Prolog 实现至少应该在此处抛出有关单例变量的警告。许多实现使它成为错误。

你的第二个子句:

reverse([A,B], ReversedList) :-
  reverse(B, TemporaryList),
  append(A, TemporaryList, ReversedList).

表示 2 项列表 ([A,B]) 的反向是通过

  • 反转列表中的第二个 item (B),并且
  • 将第一项 (A) 附加到其中。

解决方案的描述不完全正确。您可以尝试类似

reverse( []    , [] ) .  % The empty list is already reversed, what with it being atomic and all.
reverse( [H|T] , R  ) :- % a non-empty list can be reversed by decomposing it into its head and tail, and
  reverse(T,T1) ,        % - reversing the tail, and
  append(T1,H,R) .       % - appending the head to the now-reversed tail.

【讨论】:

  • 感谢您的回答。然而,这只是一个语法问题。我想写 reverse([A|B], ReversedList) insted of reverse([A,B], ReversedList)。它仍然不起作用,但我知道算法不对。
【解决方案2】:

可能还有其他问题,但是

  1. reverse([], ReversedList).
    

    几乎肯定不是你想要的。空列表的反面是空列表,翻译为

    reverse([], []).
    
  2. 另外,

    reverse([A,B], ReversedList)
    

    也可能不是您想要的。它不是具有头 A 和尾 B 的列表,而是一个 2 元素列表。

【讨论】:

  • 结果是一样的:(
  • 这就是问题所在 (nr2)。现在它没有返回正确的结果,但这是我算法中的一个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-12
  • 2013-11-09
  • 2013-05-29
  • 2020-03-16
相关资源
最近更新 更多