Parsing 在F中模拟Prolog回溯# 我目前参与了一个项目,开发一个能够考虑一组节点和连接的应用程序,并找到两个节点(允许连接)之间的最短路径(一个常见的和众所周知的问题)。我不需要从零开始构建应用程序,只需要在f#中“转换”一个Prolog预先存在的应用程序。 我想了想,最后问了自己一个问题:“我能不能创建一个程序,能够接受Prolog这样的事实,并使用它们进行查询或类似的事情,而不是开发一个特殊用途的解决方案,实现专门针对这个问题的新算法?”
通过这样做,我将创建一组事实(如在Prolog中),然后使用它们进行查询。 因此,现在考虑到这个新问题(在F#中转换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
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解释器并使用一些有区别的并集表示事实
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
感谢您的建议。。。我为这件事感到抱歉。。。什么是统一算法?我想这可能是一些有用的东西,所以请原谅我的坏知识。。。