良好的Prolog代码特点是什么?

11

要写出优秀的Prolog程序,程序员需要掌握哪些设计启发法?听说有经验的程序员需要大约两年时间才能熟练掌握Prolog。有效地使用递归是其中的一部分,但这似乎只是一个相对较小的障碍。究竟是什么让程序员遇到如此多的问题?我应该在示例代码中寻找什么来判断其质量?


6
两年之内[参见此推荐](http://norvig.com/21-days.html)——甚至不是关于Prolog的! - false
1个回答

26
写好Prolog代码的主要难点在于不仅要理解,还要充分传达程序的意图或目的。与其他编程语言相比,在同一程序中经常存在几种不同类型的Prolog代码,混淆这些级别会导致错误和问题:
纯粹、单调的代码。 这种代码是Prolog的核心。在这样的代码中,许多代数性质成立,并且实际问题以纯粹、理想的方式描述,这也是Prolog经常宣传的方式。然而,在这些部分中,某些过程性属性可能会浮出水面,例如非终止性。以合取式的交换律为例。在纯粹、单调的代码中,(A,B)和(B,A)描述了相同的关系。唯一的区别可能在于不同的终止行为和答案出现的顺序。理想情况下,纯谓词的名称应该表明这些谓词是关系。在这里,命令是绝对不是一个好选择。
具有副作用的代码。 另一个极端是只能通过机器或头脑有效执行来理解的代码。程序中没有简单的不变量。但是,在这些部分中,仍然可能观察到某些属性,如坚定性。实际上,这样的代码与其他编程语言并没有太大的区别。
经常情况下,有副作用的部分会“吞噬”纯净的部分,因为程序员习惯于命令式、面向指令的思维方式。为了朝另一个方向发展,要考虑你将失去或获得哪些属性。考虑一下测试程序的难易程度:程序越纯净,测试就越容易,不需要任何额外的沙盒。简单的顶层查询就足够了。
以下是一些例子,说明如何以牺牲看似必要的副作用来扩展纯净的部分:
- 使用手动列表迭代和递归遍历失败之间的利弊 - Prolog递归跳过相同的结果 - 或者只需这些答案
编辑:在您的评论中,您要求“学习建议”。因此,这里有一些:
  1. 坚持只编写纯的、单调的代码。只有当你了解两者时,才能判断选择哪一方。我假设你之前在某些命令导向语言中产生过副作用的经验,但没有使用纯代码的经验。因此,这意味着你将避免编写天然非单调的代码。

  2. 尝试使用toplevel。想象一下,toplevel是访问你的程序的唯一方式。如何设计问题使其符合这种格式?SWI、Scryer和Trealla toplevel专门设计为允许这种轻量级交互。

  3. 使用进行算术运算。不要使用(is)/2,它会让你的代码变得太模式化。

  4. 享受纯的、单调的代码的代数特性。想一想:你添加一个目标,无论在哪里,你都可以预测这个目标将使你的程序专业化(并且最好保持原样)。你可以盲目地删除一个目标,而仍然知道(部分)它的影响。

  5. 研究的概念以掌握非终止。

  6. 不要使用分步跟踪器/调试器,尽管它在许多Prolog中提供。它只会显示Prolog所采取的精确步骤。它不会直接显示与程序含义相关的任何内容。它强化了一种分步思维。

  7. 注意你的语言。你谈论程序的方式会影响你对它的思考方式。因此,如果你使用大量操作化的语言(比如:这个做这个等),那么你增强了命令导向视图。有一种更干净的谈论事物的方式,但你需要找到它。这可能是最难的部分。


你是说主要的困难在于知道何时在特定子问题中以命令式或声明式方式使用Prolog吗?我会期望这种知识来自于对特定系统和特定问题的丰富经验。所以我猜你无法给出太多关于学习的一般建议。 - user287424
2
@user287424:我建议这个问题:你会失去或获得多少属性?代码测试有多容易?虽然需要一些时间来详细考虑,但这也是可以回答的。经验使这变得更加容易和快速,但你可以从这开始。 - false
@j4nbur53 单调性和坚定性并不总是相关的。以append/3的第一个参数为例:它不是坚定的,但定义仍然是单调的。 - false
@false,你在这里使用的“steadfast”是什么定义?我们是否曾经就该术语应该意味着什么达成了明确的答案?请参见https://dev59.com/5lkT5IYBdhLWcg3wAK_w。 - Jason Hemann
@JasonHemann:当然不是后者,而是前者。 - false
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接