在Prolog

时间:2015-11-30 03:04:27

标签: list prolog

我正在讨论是否应该检查这两个列表是否通过除以/或​​%来检查两个列表是否都是列表是偶数并返回true或两个列表都是奇数并返回true否则返回false;使用以下代码:

evenOrOdd([],[],0).
evenOrOdd(List1, List2, Output) :-
   length(List1, N),
   length(List2, M),
(N/2 && M/2 || N%2 && M%%2 ->
    Output = List1
;   Output = List2
).

以下内容无法正确编译,我无法弄清楚问题是什么。最终我要比较的两个列表是:

[x,x,x]
[1,2,3]

但是当我去测试它时它返回了假。怎么会发生这种情况?

1 个答案:

答案 0 :(得分:3)

您的代码存在一些问题,但让我先向您展示解决方案。

evenOrOdd(L, R) :-
  length(L, N),     length(R, M),
  N mod 2 =:= M mod 2.

你要注意的第一件事是我必须创造很多临时值。 Prolog中的表达式评估实际上由is/2触发;它不会自动发生。尽管写N mod 2 = M mod 2是诱人的,但它只会统一N = M,这不是你想要的。您必须使用is/2触发评估,然后直接比较值,或使用执行评估的=:=/2(感谢@CapelliC!)。

(旁白:你通过这种暂停评估权衡实际购买的是大量的DSL建设能力,但是大多数大学的初学者都没有看到它,所以他们只是发现它毫无意义的挫折。)

现在讨论问题。

首先,您的代码有一些"类型"混淆:如果给出空列表,则最终变量与0结合;如果您获得非空列表,它将与一个或另一个列表统一。我很难想象一个有意义的场景;我不知道这是否是Python的遗留物,其中0的布尔风味为false,但非空列表的布尔风味为true。或者,可能是您认为您需要一个基本案例,即使您并未真正使用列表的归纳案例。也许第三个论点就是代表结果,因为事情必须有结果。 :)无论情况如何,它都不是非常必要或正确。

其次,你正在犯这样一个诚实的初学者错误,假设算术表达式是由Prolog评估的。这是一个诚实的错误;地球上的其他语言都是这样的,但Prolog是不同的。 N/2 && M/2 || N%2 && M %%2与语法上可接受的Prolog相差甚远。首先,%是Prolog中的注释字符;我们使用mod进行模运算(如Python)。另外,因为is/2是关于评估算术表达式的,所以没有boolean"和"的语法。和布尔"或,"只是按位,这不完全是你需要的。常规逻辑"和"和"或"分别是Prolog中的,;。但我认为这个表达方式比你需要的更复杂;你只需知道他们有相同的余数mod 2。

让Prolog的统一机制代表你传达真假,而不是用某些变量明确地统一真假,这几乎总是更好;否则你可以很容易地进入谓词已经成功的奇怪情况。在某种意义上意味着传达失败。此外,你还在使用Prolog!您应该享受回溯的好处,而不是编写程序代码。

希望这可以解决问题!