65.9K
CodeProject 正在变化。 阅读更多。
Home

Prolog for .NET Developers

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (16投票s)

2007年1月8日

7分钟阅读

viewsIcon

122273

downloadIcon

2549

面向 .NET 和 Mono 开发者的 Prolog 初体验

P# Interactive GUI

引言

2006年11月,Sacha Barber 在 Code Project 上发表了一篇有趣的文章,该文章使用经典的传教士和食人族问题来演示 C# 中的人工智能搜索技术。这个问题很简单,非常适合介绍一种替代的编程语言——人工智能语言 Prolog。

通用语言规范 (CLS) 最有趣的特性之一是默许了没有一种语言能完美解决所有问题。虽然 C# 是一种优秀的语言,但有些数学问题可能用 APL 或 SML 来表达更好,而一些逻辑问题则非常适合用 Prolog。更重要的是,CLS 允许方便的混合语言编程。这意味着我们可以用一种适合此目的的语言(例如 C#)构建用户界面,同时用一种非常适合此类搜索的语言(Prolog)来描述食人族和传教士问题。这种分离还可以提高程序的可维护性,因为核心问题代码不仅可以与用户界面分离,还可以与任何特定于平台的考虑因素分离。

我们不重复探讨食人族和传教士问题,而是使用一个类似的问题:农夫-卷心菜-山羊-狼问题。这两个问题都说明了一类通用问题,即我们必须找到一条满足严格约束的通往特定目标的路径。相同的底层问题结构出现在许多更复杂的问題中,包括符号推理、自然语言处理和认知建模。这类问题通常比用 Java 或 C# 等传统的过程式语言表达要简单得多。在讨论核心问题本身之前,让我们先看看希望探索 Prolog 的 .NET 或 Mono 开发者的可用选项。

市面上有很多优秀的 Prolog 实现,包括一些出色的开源软件包。当然,每个都有其优缺点。在我看来,对 .NET 开发者最感兴趣的两个是 XSB 和 P#。XSB 是一个顶尖的人工智能编程平台。实际上,称它为 Prolog 并不公平;XSB 是 Prolog 的超集。虽然它能运行 Prolog 代码,但它支持许多严格来说不属于 Prolog 语言的强大功能和扩展。XSB 是开源的,并且适用于包括 Windows 和 Linux 在内的许多平台。然而,其编译后的代码运行在非托管环境中。使用 XSB 作为组件的 .NET 开发者必须非常熟悉调用 API 级别的过程。另一方面,P# 是 Jon Cook 专门为 CLR 创建的开源 Prolog 实现。虽然不如 XSB 功能强大,但它对于希望将规则驱动的 Prolog 代码嵌入 C# 程序中的开发人员来说是一个绝佳的工具。(向 Cook 先生致敬!)

P# 可以有两种使用方式:作为 Prolog 解释器或作为 Prolog 到 C# 的编译器。如果只是想解决传教士和食人族问题,解释器会是理想的选择。他或她可以编写 Prolog 代码,在解释器中运行,然后得到答案。解释器也非常适合初学者;可以在一个简单舒适的环境中开发和探索简单的 Prolog 规则。相比之下,如果正在开发一个专家系统,例如系统诊断,那么将 Prolog 代码编译成 C# 并将生成的代码嵌入到更大的应用程序中可能更有价值。

背景

要理解这个例子,需要了解一些 Prolog 的基础知识。Prolog 的语法相当严格。变量名以大写字母开头,小写字母用于表示固定值和 Prolog 项。变量的工作方式与您习惯使用的过程式编程语言(也许是 C#)中的变量大不相同。Prolog 变量类似于高中代数中的变量,其操作方式与逻辑学家所谓的“合一”非常相似。也就是说,给定一个变量,Prolog 会搜索其事实,并尝试确定是否存在一个变量值可以使某个陈述为真。在 Prolog 中,通常根本不给变量赋值。

Prolog 的教材经常选择家谱作为入门示例(顺便说一句,这是 Prolog 的一个绝佳应用)。事实 father('Abraham','Isaac'). 表明了这两个程序性原子 'Abraham' 和 'Isaac' 在名为 father 的子句中相关。然后,我们可以用 father(X,'Isaac'). 来查询我们的一行数据库。

要在交互式环境中测试这一点,我们必须将任何新事实“断言”到当前会话中。这里是一个交互式 Prolog 会话的副本

| ?- assert(father('Abraham','Isaac')).

yes
| ?- father(X,'Isaac').

X = Abraham ? 

yes
| ?- 

Prolog 跟踪完数据库后,它发现当 X = Abraham 时,查询为真。

使用代码

可以公平地说,Prolog 编程不能在一下午学会,但传教士-食人族问题或农夫-卷心菜-山羊-狼问题可以说明 Prolog 的工作原理。在 C# 等过程式语言中,值被赋给变量。在 Prolog 中,变量更类似于您高中代数中使用的变量。Prolog 代码会寻找能满足 Prolog 代码中定义的规则约束的变量值。

这里有一个 Prolog 规则的例子;它很简单,但又不熟悉,所以需要一点时间来适应。我们使用 "state(F,G,C,W)" 来描述这个小戏剧中四个主人公的位置。例如,state(n,n,s,s) 表示农夫和山羊在北岸,卷心菜和狼在南岸。然后,我们可以定义一组 Prolog 规则来定义允许的状态转换。例如,以下规则要求农夫和山羊(位置 1 和 2)可以转移到对岸,同时狼和卷心菜的位置保持不变。

transition(state(F0,F0,C,W), state(F1,F1,C,W)):-
    opposite(F0,F1).

为每一种允许的转换定义了类似的规则。

现在,让我们在 P# 交互环境中运行程序。启动程序 PSharpGUI.exe。可以通过通常的“文件\打开”对话框将 Prolog 文件加载到编辑器中。但是,要交互式地使用文件中的事实和规则,该文件还必须在 Prolog 环境本身中打开。如果文件不需要编辑,可以直接打开。由于 Prolog 文件由 Prolog 事实组成,将此类文件打开到环境中称为“咨询”它。我们将需要咨询一组标准实用程序:list.pl 和农夫-山羊规则文件 farmergoat.pl。

consult('list').
consult('farmergoat').

请注意,不包含文件扩展名,并且务必不要忘记 consult 子句末尾的点号。

许多 Prolog 程序都会有一个“main”子句或一个“go”子句,在文件被咨询时自动运行。在这种情况下,通过键入一个子句,我们可以学到更多东西

path(state(n,n,n,n),state(s,s,s,s), FinalPath).

这个子句成为了我们的目标;我们想找到一系列允许的转换,将我们从起始状态(所有人在北岸)带到最终状态(所有人在南岸)。如果存在这样的状态序列,它将与变量 FinalPath“统一”。虽然我们在这里不讨论,但 Prolog 完全有能力返回并找到其他可能的解决方案。

这是 farmergoat.pl 的完整代码

opposite(n,s).
opposite(s,n).


/* farmer crosses with goat */

transition(state(F0,F0,C,W), state(F1,F1,C,W)):-
    opposite(F0,F1).

/* farmer crosses with cabbage */

transition(state(F0,G,F0,W), state(F1,G,F1,W)):-
    opposite(F0,F1),
    opposite(G,W).

/* farmer crosses with wolf */

transition(state(F0,G,C,F0), state(F1,G,C,F1)):-
    opposite(F0, F1),
    opposite(G,C).

/* farmer crosses alone */

transition(state(F0,G,C,W), state(F1,G,C,W)):-
    opposite(F0,F1),
    opposite(G,C),
    opposite(G,W).


path(A,B,FinalPath):- 
    path(A,B,[], ReversedFinalPath),
    reverse(ReversedFinalPath, FinalPath).

path(CurState, GoalState,PrevStates, [GoalState|PrevStates]):-
    transition(CurState, GoalState).

path(CurState, GoalState, PrevStates, FinalPath):-
    transition(CurState, NextState),
    not(member(NextState, PrevStates)),
    path(NextState, GoalState, [CurState|PrevStates], FinalPath).

对于希望了解更多关于 Prolog 的开发人员来说,有几本优秀的教材,但就我个人而言,入门最好的还是 Ivan Bratko 出版的、由 Addison Wesley 出版的杰作《PROLOG Programming for Artificial Intelligence》。有兴趣的开发者也欢迎联系本文的作者。那些不仅感兴趣而且怀旧的人将收到一个命令行经典游戏“Hunt the Wumpus”的 Prolog 实现。

关注点

尽管 Prolog 已经存在了三十多年,但它最近在包括自然语言处理在内的许多领域重新受到关注。作者特别感兴趣的是使用 Prolog 从大型数据库生成假设。

关于 Dan Buskirk

P# Interactive GUI Dan Buskirk 是一位专业的 SQL Server 开发者和 .NET 程序员。他很少能抵挡住探索新奇有趣事物的诱惑。

© . All rights reserved.