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

Parsing 在F中模拟Prolog回溯# 我目前参与了一个项目,开发一个能够考虑一组节点和连接的应用程序,并找到两个节点(允许连接)之间的最短路径(一个常见的和众所周知的问题)。我不需要从零开始构建应用程序,只需要在f#中“转换”一个Prolog预先存在的应用程序。 我想了想,最后问了自己一个问题:“我能不能创建一个程序,能够接受Prolog这样的事实,并使用它们进行查询或类似的事情,而不是开发一个特殊用途的解决方案,实现专门针对这个问题的新算法?”,parsing,f#,prolog,language-design,pattern-matching,Parsing,F#,Prolog,Language Design,Pattern Matching,通过这样做,我将创建一组事实(如在Prolog中),然后使用它们进行查询。 因此,现在考虑到这个新问题(在F#中转换Prolog),我需要找到一种方法来创建如下事实: myfact1(el1, el2,..., eln). myfact2(el1, el2,..., elm). ... myfactk(el1, el2,..., elp). 以类似的语法执行以下操作: fact factname1: el1 el2 ... eln; fact factname2: el1 el2 ... el

通过这样做,我将创建一组事实(如在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#非常适合解析,所以我认为解析这可能不是问题

好的!既然已经解析了,我应该定义一个算法,在解析代码时,将所有事实存储在某种知识中(只不过是一个表)。为了建立所有必要的联系

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

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; 事实母亲:cd

我的哈希表是:

母亲->A | B 母亲->C|D

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

如果我想搜索:“谁是B的母亲”-->我搜索母亲,然后寻找值,我找到B,我在元组中找到A

嗯,它似乎起作用了。 但事实很容易实现。规则呢? 例如,规则父母:

parents(A, B, C) :- mother(A, C), father (B, C)
用我的语法?我想到了这个主意:

rule parents: A, B, C => mother A C and father B C
当解析器遇到规则时,它应该做什么?我想像以前一样在表中创建某种记录,以后可以进行查询,以便指定一个主题并获取其父对象,或者指定一个父对象并获取所有子对象,等等。。。 你会怎么做?

最近有关于将类似Prolog的程序集成到F#中的问题

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])))

从前,我认识一个人,他写了一封信。他一直想为F#做同样的事,但始终没有找到时间。他似乎还记得基本的prolog统一&回溯算法非常简单(也许是流行方案文本的最后一章中的练习?),希望有人能击败他,因为他正在度假。:)

一个好的起点是在F#中实现Prolog风格的统一算法。好的伪代码或LISP实现可以在许多通用a.I.教科书或web上找到。您可以从这一点向外工作到回溯和语法。统一算法应该非常简单,可以用F#等功能丰富的语言实现(尽管可能有点神秘)。

谢谢你的回答,佩特里切克先生。请只做一件事。。。你能编辑你的答案并张贴你将用来创建歧视联盟的代码吗?非常感谢。@Andry:是的,我为变量、表达式和规则添加了一个简单的类型声明。非常感谢你,Petricek先生:)啊,我注意到一件事:类型规则似乎是一个有区别的并集,但它有一个“成员”,其名称与类型相同。。。它是某种递归联合定义吗?还是怎样(正如你看到的,我在这里算是个新手……@Andry:不,这不是一个骗局——只是一个歧视性的联盟,只有一个案例(名字可以是其他任何东西)。我们可以为
Var
Rule
使用其他类型(例如记录或F#object),但我使用了判别并集,因为它使模式匹配更容易。例如,如果您正在编写函数以返回规则的变量数,则可以编写
let numVars(rule(u,args,))=args.Length
感谢您的建议。。。我为这件事感到抱歉。。。什么是统一算法?我想这可能是一些有用的东西,所以请原谅我的坏知识。。。