当我想阅读逻辑编程时,时下我总是会遇到两种“主要”方法:
- miniKanren,在The Reasoned Schemer中引入的一种迷你语言,由于core.logic的缘故,目前很受欢迎。
- Prolog,第一种“大”逻辑编程语言。
我现在感兴趣的是:两者之间的主要技术区别是什么?它们在方法和实现上是否非常相似,还是对逻辑编程采用完全不同的方法?它们来自哪些数学分支,其理论基础是什么?
当我想阅读逻辑编程时,时下我总是会遇到两种“主要”方法:
我现在感兴趣的是:两者之间的主要技术区别是什么?它们在方法和实现上是否非常相似,还是对逻辑编程采用完全不同的方法?它们来自哪些数学分支,其理论基础是什么?
Answers:
首先,请允许我赞扬您的pw0n1e图标。
这是一个棘手的问题,主要是因为miniKanren和Prolog的变体太多。miniKanren和Prolog实际上是语言家族,这使得很难比较它们的功能,甚至很难比较它们在实践中的用法。因此,请谨慎处理我要说的一切:如果我说Prolog使用深度优先搜索,请注意,许多Prolog实现都支持其他搜索策略,并且其他搜索策略也可以在meta处进行编码。 -解释器级别。不过,miniKanren和Prolog具有不同的设计理念,并会做出不同的取舍。
Prolog是用于符号人工智能编程的两种经典语言之一(另一种经典语言是Lisp)。Prolog擅长实现基于符号规则的系统,其中声明性知识以一阶逻辑编码。该语言针对这些类型的应用程序的表达性和效率进行了优化,有时会牺牲逻辑的纯度。例如,默认情况下,Prolog不统一使用“出现检查”。从数学/逻辑的角度来看,此版本的统一是不正确的。但是,发生检查很昂贵,并且在大多数情况下,缺少发生检查不是问题。这是一个非常务实的设计决策,Prolog使用深度优先搜索和使用cut(!
)来控制回溯。我确信这些决定在1970年代的硬件上运行时绝对必要,而今天在处理大问题时以及在处理巨大(通常是无限!)搜索空间时非常有用。
Prolog支持许多“额外逻辑”或“非逻辑”功能,包括cut assert
和and retract
变量的投影,以便使用is
等等。这些功能中的许多功能使表达复杂的控制流程和操纵Prolog的全球事实数据库变得更加容易。Prolog的一个非常有趣的功能是Prolog代码本身存储在事实的全局数据库中,并且可以在运行时进行查询。这使得编写修改解释中的Prolog代码行为的元解释器变得微不足道。例如,可以使用更改搜索顺序的元解释器在Prolog中对广度优先搜索进行编码。这是一种非常强大的技术,在Prolog世界之外尚不为人所知。“序言的艺术”详细介绍了此技术。
改进Prolog的实现已付出了巨大的努力,其中大多数基于Warren Abstract Machine(WAM)。WAM使用一种副作用模型,在该模型中,将值破坏性地分配给逻辑变量,而在回溯时这些副作用被撤消。通过扩展WAM的说明,可以将许多功能添加到Prolog中。这种方法的一个缺点是,如果没有对WAM的深入了解,可能很难阅读Prolog实施文件。另一方面,Prolog实施者具有讨论实施问题的通用模型。在并行的Prolog中进行了大量的研究,最终在1990年代的Andorra Prolog中达到顶峰。这些想法中至少有一些存在于Ciao Prolog中。(Ciao Prolog充满了有趣的想法,其中许多远远超出了Prolog的标准。)
Prolog具有漂亮的基于统一的“模式匹配”样式的语法,从而导致程序非常简洁。序言者喜欢他们的语法,就像利珀斯喜欢他们的s表达式一样。Prolog还具有大量的标准谓词库。由于使WAM快速运行的所有工程技术,因此有非常强大且成熟的Prolog实现。结果,许多大型的基于知识的系统已完全用Prolog编写。
miniKanren被设计为一种最小的逻辑编程语言,具有一个小型,易于理解和易于破解的实现。miniKanren最初嵌入在Scheme中,并且在过去十年中已移植到其他数十种宿主语言中。miniKanren最流行的实现是Clojure中的'core.logic',它现在具有许多类似Prolog的扩展和许多优化。最近,miniKanren实现的核心得到了进一步简化,从而产生了一个名为“ microKanren”的微型“微内核”。然后,可以在此microKanren核心之上实现miniKanren。将microKanren或miniKanren移植到新的宿主语言已成为学习miniKanren的程序员的标准练习。结果是,
miniKanren和microKanren的标准实现不包含任何突变或其他副作用,唯一的例外是:某些miniKanren版本使用指针相等性来比较逻辑变量。我认为这是“良性效果”,尽管许多实现甚至通过在实现中传递计数器来避免这种效果。也没有全局事实数据库。miniKanren的实现哲学受到函数式编程的启发:应避免突变和影响,所有语言构造应遵循词汇范围。如果仔细看一下实现,您甚至可能会发现几个monad。搜索实现基于合并和处理惰性流,再次不使用任何突变。这些实现选择导致的权衡与Prolog不同。在Prolog中,变量查找是固定时间,但是回溯需要消除副作用。在miniKanren中,变量查找更为昂贵,但回溯是“免费的”。实际上,由于如何处理流,miniKanren中没有回溯。
miniKanren实现的一个有趣的方面是,该代码本质上是线程安全的,并且-至少从理论上讲-可以并行化。当然,考虑到必须为每个线程或进程提供足够的工作来弥补并行化的开销,并行化代码而不降低速度并非易事。尽管如此,这还是miniKanren实施的一个领域,我希望它将得到更多关注和试验。
miniKanren使用出现检查进行统一,并使用完整的交织搜索而不是深度优先搜索。交错搜索比深度优先搜索使用更多的内存,但是在深度优先搜索将永远发散/循环的某些情况下,可以找到答案。miniKanren 不支持一些额外的逻辑操作符- conda
,condu
以及project
,例如。 conda
和condu
可用于模拟的Prolog的切口,并且project
可以被用来获得与一个逻辑变量相关联的值。
的存在下conda
,condu
和project
---以及轻松修改搜索策略的能力---允许程序员使用miniKanren作为类似于Prolog的嵌入式语言。对于Clojure的'core.logic'用户而言尤其如此,其中包括许多类似于Prolog的扩展。miniKanren的这种“实用”用法似乎占miniKanren在工业中的大多数使用。希望将基于知识的推理系统添加到用Clojure或Python或JavaScript编写的现有应用程序中的程序员通常对用Prolog重写整个应用程序不感兴趣。在Clojure或Python中嵌入小型逻辑编程语言更具吸引力。大概,为此目的,嵌入式Prolog实现也将很好地工作。
除了将miniKanren用作与Prolog精神相似的实用嵌入式逻辑编程语言外,miniKanren还被用于“关系”编程中的研究。也就是说,在编写程序时,它们表现为数学关系而不是数学函数。例如,在Scheme中,该append
函数可以追加两个列表,并返回一个新列表:函数调用(append '(a b c) '(d e))
返回list (a b c d e)
。但是,我们也可以将其append
视为三位关系而不是二元函数。(appendo '(a b c) '(d e) Z)
然后,该调用会将逻辑变量Z
与列表相关联(a b c d e)
。当然,当我们将逻辑变量放在其他位置时,事情会变得更加有趣。呼叫(appendo X '(d e) '(a b c d e))
关联X
用(a b c)
,而通话(appendo X Y '(a b c d e))
关联,X
并Y
与附加后等于的列表对成对(a b c d e)
。例如,X
= (a b)
和Y
= (c d e)
是一对这样的值。我们也可以写(appendo X Y Z)
,这将产生清单的无限多三倍X
,Y
和Z
这样追加X
到Y
生产Z
。
的这种关系版本append
可以轻松地在Prolog中表达,并且确实在许多Prolog教程中都有展示。在实践中,更复杂的Prolog程序倾向于至少使用一些额外的逻辑功能,例如cut,这会限制将生成的程序视为关联的能力。相反,miniKanren专门设计为支持这种类型的关系编程。最近miniKanren的版本有象征性的约束求解的支持(symbolo
,numbero
,absento
,不等式约束,标称逻辑编程),从而更轻松地将非平凡程序编写为关系。在实践中,我从不使用miniKanren的任何逻辑外功能,而是将所有miniKanren程序编写为关系。最有趣的关系程序是Scheme子集的关系解释器。这些解释器具有许多有趣的功能,例如生成一百万个对列表进行求值的Scheme程序(I love you)
,或平凡地生成quines(对自己求值的程序)。
miniKanren进行了一些权衡以实现这种关系编程风格,这与Prolog进行的权衡非常不同。随着时间的流逝,miniKanren增加了更多的符号约束,实际上成为了一种面向符号的约束逻辑编程语言。在许多情况下,这些符号约束使避免使用诸如condu
和之类的逻辑外运算符变得切实可行project
。在其他情况下,这些符号约束是不够的。更好地支持符号约束是miniKanren研究的一个活跃领域,也是一个更广泛的问题,即如何编写更大和更复杂的程序作为关系。
简而言之,miniKanren和Prolog都具有有趣的功能,实现和用法,我认为值得从这两种语言中学习思想。还有其他非常有趣的逻辑编程语言,例如Mercury,Curry和Gödel,每种语言都有自己的逻辑编程语言。
我将以一些miniKanren资源结尾:
miniKanren的主要网站:http ://minikanren.org/
我对关系编程和miniKanren进行了一次采访,其中包括与Prolog的比较:http : //www.infoq.com/interviews/byrd-relational-programming-minikanren
干杯,
- 将
暂定答案:
AFAIK,“理性的计划者”以Scheme-y语法和函数式编程风格介绍了基本逻辑编程,特别是将常量目标“ #u”(失败)和“ #s”(推导)添加到布尔值“ #t”中”和“ #f”。它使用与Prolog相同的逻辑编程方法:统一和回溯搜索。我将看看周末是否有时间从书架上取回那本书。数学的分支是一种受限形式的一阶逻辑,在这种情况下是Horn子句,以及Resolution Unfication。请参阅:《计算逻辑:过去的回忆和对未来的挑战》,约翰·艾伦·罗宾逊(John Alan Robinson)和罗伯特·科瓦尔斯基(Robert Kowalski)的逻辑编程的早期,是一个冷门。