Haskell 推理机中的规则和事实(循环?)定义

Haskell 推理机中的规则和事实(循环?)定义,haskell,recursive-datastructures,cyclic-reference,inference-engine,Haskell,Recursive Datastructures,Cyclic Reference,Inference Engine,作为一个学校项目,我正在研究一个反向链接引擎。 到目前为止,我大部分都是用C语言完成项目的,所以我决定用Haskell来完成这个项目。我阅读了LYAH以便开始,并开始在我的推理机中实现规则和事实的表示。 到目前为止,这就是我得到的 模块推理(),其中 输入Op=Bool->Bool->Bool 类型标签=字符串 类型事实=(标签,[规则]) 数据规则=操作规则操作规则 |事实事实 评估事实::[Label]->fact->Bool eval_事实证明(标签,规则)=标签'elem'证明| |任何

作为一个学校项目,我正在研究一个反向链接引擎。 到目前为止,我大部分都是用C语言完成项目的,所以我决定用Haskell来完成这个项目。我阅读了LYAH以便开始,并开始在我的推理机中实现规则和事实的表示。 到目前为止,这就是我得到的

模块推理(),其中
输入Op=Bool->Bool->Bool
类型标签=字符串
类型事实=(标签,[规则])
数据规则=操作规则操作规则
|事实事实
评估事实::[Label]->fact->Bool
eval_事实证明(标签,规则)=标签'elem'证明| |任何(eval_规则证明)规则
评估规则::[Label]->规则->布尔
已证明的评估规则(事实x)=已证明的评估规则x
已证明的eval_规则(操作r op r')=已证明的eval_规则r`op`eval_规则已证明r'
其思想是要有某种图形,其中事实节点指向规则节点,除非事实已经在已知事实列表中

然而,在这里我遇到了定义我的实际事实和规则的问题

做一些事情,比如

let fact_e = ("E", [Fact ("C", [(Operation (Fact ("A", [])) (||) (Fact ("B", [])))])])
在ghci中,以表示规则

C => E
A || B => C
这很有效。但我真的看不出以编程方式构造这些规则的方向。此外,我不知道如何使用该方案处理循环规则(例如添加规则
E=>a

我已经看到,在haskell wiki上,有一些方法可以通过称为“打结”的技巧来定义haskell中的自引用数据结构,但我不知道在本例中应该如何(甚至是否)应用这些方法

我的问题本质上是,我是朝着正确的方向走,还是完全倒退了


附言:在我看来,我的代码似乎没有它应该的那么简洁(在[Label]列表中传递,多次重复
eVal_rule Provided
),但我真的不知道如何用另一种方式来实现它。

这个想法是首先将规则解析成一个非自引用的中间表示形式。例如,给定表示:

type Program = [(Label, [Rule_P])]
data Rule_P = Operation_P Rule_P Op Rule_P | Fact_P Label
然后是一组规则:

C => E
A || B => C
E => A
F => E
将被解析,由隐含目标收集,并表示为:

prog1 :: Program
prog1 = [ ("E", [ Fact_P "C"                                       -- C => E
                , Fact_P "F" ])                                    -- F => E
        , ("C", [ Operation_P (Fact_P "A") (||) (Fact_P "B") ])    -- A || B => C
        , ("A", [ Fact_P "E" ]) ]                                  -- E => A
然后,要将其转换为循环自参考知识库(使用原始的
Fact
类型):

你是这样打结的:

learn :: Program -> Knowledge
learn program = knowledge

  where

    knowledge :: [Fact]
    knowledge = [ (target, map learn1 rules_p) | (target, rules_p) <- program ]

    remember lbl = fromJust (find ((==lbl) . fst) knowledge)

    learn1 :: Rule_P -> Rule
    learn1 (Fact_P lbl) = Fact (remember lbl)
    learn1 (Operation_P rule1 op rule2) = Operation (learn1 rule1) op (learn1 rule2)
当然,尝试:

> eval_fact [] $ fromJust $ find ((=="E").fst) (learn prog1)

将循环直到内存耗尽,因为它尝试(未成功)从C从E从A从E证明E,等等,所以您需要添加一些逻辑来中止循环证明。

您不是已经通过编程方式构建规则了吗?也就是说,您已经在使用编程指定规则,如
fact\e
。对于循环规则,您应该能够将它们全部放入一个
let
块中(例如
let x1=val1 x2=val2 x3=val3 in
),并让惰性自动排序循环性。至于你的附言:为了传递
[Label]
,试着学习一下“
阅读器”
monad”。如果您使用
Reader
,重复
eval_规则也会变得更好。我的意思是,我不知道如何动态执行(例如通过解析文件)而不是静态地将它们写在代码中。关于
let
,这就是我正在尝试的,thxs:)。要动态生成
事实的列表,您应该能够像其他任何数据结构一样执行此操作。例如,如果您有
C=>E
,您可以将其拆分为
[“C”、“=>”、“E”]
,然后编写函数将列表中的各个项转换为
操作
和其他
事实
项,然后使用适当的构造函数将它们组合在一起。如果你不知道自己到底在做什么,就很难说出更多的话;您是否正在努力解析
字符串
,或者将解析的
字符串
转换为
事实
?我的问题更多的是规则的可能自引用。将我的源代码解析为我的表示并不困难,但将其转换为自引用表达式则有点困难。我想,@K.A.布尔的答案正是我想做的。
> know1 = learn prog1
> Just [Operation factA _ _] = lookup "C" know1
> Fact ("A", [factE]) = factA
> Fact ("E", [factC, _]) = factE
> Fact ("C", [Operation factA' _ _]) = factC
> Fact ("A", [factE']) = factA'
> eval_fact [] $ fromJust $ find ((=="E").fst) (learn prog1)