【发布时间】:2019-06-20 15:20:32
【问题描述】:
我正在开发一个反向链接引擎作为一个学校项目。 到目前为止,我主要是用 C 语言完成项目,所以我决定为那个项目尝试 Haskell。我已经阅读了 LYAH 以开始并开始在我的推理引擎中实现规则和事实的表示。 到目前为止,这就是我得到的
module Inference () where
type Op = Bool -> Bool -> Bool
type Label = String
type Fact = (Label, [Rule])
data Rule = Operation Rule Op Rule
| Fact Fact
eval_fact:: [Label] -> Fact -> Bool
eval_fact proved (label,rules) = label `elem` proved || any (eval_rule proved) rules
eval_rule:: [Label] -> Rule -> Bool
eval_rule proved (Fact x) = eval_fact proved x
eval_rule proved (Operation r op r') = eval_rule proved r `op` eval_rule proved r'
这个想法是要有某种图表,其中事实节点指向规则节点,除非事实已经在已知事实列表中。
但是,在这里我遇到了定义我的实际事实和规则的问题。
做类似的事情
let fact_e = ("E", [Fact ("C", [(Operation (Fact ("A", [])) (||) (Fact ("B", [])))])])
在 ghci 中为了表示规则
C => E
A || B => C
这行得通。但是我真的不知道以编程方式构建这些规则的方向。此外,我看不到如何使用该方案处理循环规则(例如添加规则E => A)。
我已经看到有一些方法可以在 Haskell 中使用 Haskell wiki 上称为“打结”的技巧来定义自引用数据结构,但我不知道应该如何(或什至)在本案。
我的问题本质上是,我是在朝着正确的方向前进,还是用这种方法完全倒退了?
PS:在我看来,我的代码也没有应有的简洁(传递 [Label] 列表,重复 eVal_rule proved 很多次......),但我也不知道如何用另一种方式来做。
【问题讨论】:
-
您不是已经以编程方式构建规则了吗?也就是说,您已经使用编程指定了诸如
fact_e之类的规则。对于循环规则,您应该能够将它们全部放入一个let块(例如let x1 = val1 <newline> x2 = val2 <newline> x3 = val3 in _),并让惰性自动整理循环。至于您的 P.S.:为了传递[Label],请尝试了解“Readermonad”。如果你使用Reader,eval_rule proved的重复应该会更好一些。 -
我的意思是我不知道如何动态地执行它(例如通过从文件中解析),而不是在代码中静态地写下来。关于
let,这就是我正在尝试的,谢谢:)。 -
对于动态生成
Facts 的列表,您应该能够像任何其他数据结构一样执行此操作。例如,如果您有C => E,您可以将其拆分为["C", "=>", "E"],然后编写函数将列表中的各个项目转换为Operations 和其他Facts,然后使用适当的方法将它们组合在一起构造函数。如果不确切知道自己坚持什么,很难说除此之外的其他内容。您是否正在为解析String或将解析后的String转换为Fact而苦苦挣扎? -
我的麻烦更多在于规则的可能自我引用。将我的源代码解析为我的表示并不难,但翻译成自我引用的表达有点困难。我的答案来自@K。 A. Buhr 正是我想要做的。
标签: haskell recursive-datastructures cyclic-reference inference-engine