有没有一种方法可以使用 write/1 来编写 length/1 谓词来打印结果?

Is there a way to write a length/1 predicate using write/1 to print result?

我有一个学校作业,最近开始学习Prolog。
这是练习(非常简单):

Write a program in Prolog to find a length of a given list. For example, length([a, b, c, d, e]). should print 5

我真的不知道如何创建一个 length/1 谓词来为我做这件事。这是我的代码:

length([],0).
length([_|T],N) :- length(T,X), N is X+1. 

现在,我问我的老师如何将其转换为 length/1 谓词,他告诉我使用 write/1 谓词。 我查找了 write/1 谓词,但看不出这将如何帮助我编写 length/1 谓词。 有人 tips/tricks 可以这样做吗?
要清楚,这是作业。

解决方法很简单:impure(Ls) :- length(Ls, L), write(L).

但是,出于几个原因,这是一个非常糟糕的主意

一个非常重要的一点是,只出现在屏幕上的东西无法在 Prolog 中被推理

因此,如果您只是用 write/1 写一些结果,您就无法真正 运行 自动测试用例来查看您的谓词是否确实按预期运行。这样至少编写测试变得更难

相比之下,使用您原始的 更纯净 版本的代码(未使用副作用),您可以轻松测试,例如:

?- length([a,b,c], 3).
true.

还有运行几个这样的自动测试用例,用Prolog看是否成功。例如,一批 10,000 个测试用例可能看起来像(搜索反例):

?- between(1, 10_000, L), length(Ls, L),  length([_|Ls], L1), L1 =\= L+1.
false.

相比之下,如何测试不纯谓词?

?- between(1, 10_000, L), length(Ls, L),  impure([_|Ls])  what now??

如您所见,对谓词的输出进行推理真的很难!

此外,这使您的谓词 比当前版本更不通用 !您不能再在其他方向使用不纯版本。例如,您现在如何生成给定长度的列表?无法提供长度!

保持纯真,使用 Prolog 顶层获取答案,而不是在屏幕上自己写!

TL;DR: 不要!

您绝对想要的在Prolog中可以实现的,但是问问自己“我应该那样做吗?”。

我给你的建议是:

  1. 不要使用 Prolog 的低级 I/O API (write/1, nl/0, ...) 因为它是基于.

  2. 在定子句语法上使用 ! Start by reading this fine Prolog primer

  3. 熟悉(并使用!)