模拟Pr#中的Prolog回溯

时间:2010-12-17 23:30:43

标签: parsing f# prolog language-design pattern-matching

我目前正参与一个项目,开发一个能够考虑一组节点和连接的应用程序,并找到两个节点之间的最短路径(一个常见且众所周知的问题)(在允许的连接上)。好吧,我不需要从零构建应用程序,但只需要在f#中“转换”Prolog预先存在的应用程序。 我以为我对此有所了解,最后问自己一个问题:“我可以创建一个能够接受像Prolog这样的事实并使用它们来进行查询的程序,而不是开发一个特殊用途的解决方案并实现专门针对这个问题的新算法。相似?”。

通过这样做,我将创建一组事实(如在Prolog中),然后使用它们进行查询。 那么,考虑到现在这个新问题(在F#中转换Prolog),我需要找到一种方法来创建这样的事实:

myfact1(el1, el2,..., eln).
myfact2(el1, el2,..., elm).
...
myfactk(el1, el2,..., elp).

使用类似语法的内容:

fact factname1: el1 el2 ... eln;
fact factname2: el1 el2 ... elm;
...
fact factnamek: el1 el2 ... elp;

我知道F#非常适合解析,所以我认为解析这个可能不是问题。

OK!现在它被解析了,我应该定义一个算法,在解析代码时,将所有事实存储在某种知识中(仅仅是一个表)。为了使所有需要的关联。

例如,解决方案可能是考虑所有关联的哈希表

factname1 -> el1
factname1 -> el2
...
factname1 -> eln
factname2 -> el1
factnale2 -> el2
...
factname2 -> elm
factname3 -> el1
...
...
factnamek -> el1
factnamek -> el2
...
factnamek -> elp

通过这样做,我将始终能够解决查询。 例如,考虑以下Prolog事实

mother(A, B) % This means that A is mother of B
mother(C, D)

在F#中我创建了

事实上母亲:A B; 事实上母亲:C D;

我的哈希表是:

母亲 - > A |乙 妈妈 - > C | d

第一个col是事实名称,第二个是值(这里是一个元组)。

如果我想搜索:“谁是B的母亲” - >我寻找母亲,寻找价值,我找到B,我看着元组,发现A!

好吧看起来很有效。 但事实很容易实现。规则怎么样? 例如规则父母:

parents(A, B, C) :- mother(A, C), father (B, C)

在F#中使用我的语法?我想出了这个想法:

rule parents: A, B, C => mother A C and father B C

当我的解析器遇到规则时,该怎么办?我想像我一样在表格中创建某种记录,以后能够进行查询以指定主题并获得其父母或指定父亲并获得所有儿子等等...... 你会做什么?

3 个答案:

答案 0 :(得分:9)

最近有关于将类似Prolog的程序集成到F#中的was a similar question

F#没有内置支持基于回溯执行搜索(如Prolog)。您基本上有两种选择:

  • 使用递归和编码回溯自己在F#中重新实现算法。
  • 使用一些受歧视的联盟实施Prolog解释器并表示事实。

为了实现最短路径搜索,我可能只是直接在F#中实现算法(使用函数式编程将非常方便,并且使用Prolog没有特别的原因)。

如果你想实现一个解释器,你可能会使用一个有区别的联合,允许你用这样的父母重写你的例子:

type Var = Var of string
type Expression = 
  | Binary of string * Expression * Expression
  | Fact of string * Expression list
  | Ref of Var
type Rule =
  | Rule of string * Var list * Expression

/// Simplified syntax for writing And
let And(a, b) = Binary("and", a, b)

let a, b, c = Var("A"), Var("B"), Var("C")
Rule("parents", [a; b; c], 
  And(Fact("mother", [Ref a; Ref c]), Fact("father", [Ref b; Ref c])))

答案 1 :(得分:2)

一个好的开始是在F#中实现Prolog风格的统一算法。良好的伪代码或LISP实现可以在许多通用A.I.中找到。教科书或在网上。你可以从那里向外工作到回溯和语法。在F#等功能丰富的语言中实现统一算法应该相当简单(尽管可能有点神秘)。

答案 2 :(得分:1)

曾几何时,我认识一个写EDSL for Prolog in C++的人。他一直有意为F#做同样的事情,但从来没有找到时间。他似乎记得基本的序言统一&回溯算法是非常简单的(在一个受欢迎的Scheme文本的后期章节,也许是一个练习?)并且希望有人会打败他,因为他正在度假。 :)