在没有实现嵌入式逻辑编程语言的情况下,是否有可扩展,有效的方法在Haskell中编写存在语句?通常,当我实现算法时,我想表达存在量化的一阶语句,如
∃x.∃y.x,y ∈ xs ∧ x ≠ y ∧ p x y
其中∈
在列表上重载。如果我赶时间,我可能会写出看起来像
find p [] = False
find p (x:xs) = any (\y -> x /= y && (p x y || p y x)) xs || find p xs
或
find p xs = or [ x /= y && (p x y || p y x) | x <- xs, y <- xs]
但是这种方法并不能很好地概括为返回多个arities的值或谓词或函数的查询。例如,即使是像
这样的简单陈述∃x.∃y.x,y,z ∈ xs ∧ x ≠ y ≠ z ∧ f x y z = g x y z
需要编写另一个搜索程序。这意味着大量的样板代码。当然,实现缩小或解析引擎的Curry
或Prolog
等语言允许程序员编写如下语句:
find(p,xs,z) = x ∈ xs & y ∈ xs & x =/= y & f x y =:= g x y =:= z
大量滥用表示法,它执行搜索并返回值。在实现形式上指定的算法时经常会出现此问题,并且通常通过fmap
,foldr
和mapAccum
等函数的组合来解决,但主要是显式递归。在Haskell中编写这样的代码是否有更通用,更高效,或者只是一般和富有表现力的方式?
答案 0 :(得分:6)
有一个允许你转换的标准转换
∃x ∈ xs : P
到
exists (\x -> P) xs
如果您需要制作证人,可以使用find
代替exists
。
在Haskell中进行这种抽象而不是逻辑语言真正令人讨厌的是,你真的必须必须将“Universe”集xs
作为参数传递。我相信这就是你在标题中提到的“大惊小怪”。
当然,如果您愿意,您可以将通用集(通过其搜索)填充到monad中。然后,您可以定义自己的exists
或find
版本以使用monadic状态。为了提高效率,你可以尝试Control.Monad.Logic,但这可能涉及对奥列格的论文的打击。
无论如何,经典编码是用lambdas替换所有绑定结构,包括存在和通用量词,并继续进行适当的函数调用。我的经验是,这种编码甚至适用于具有大量结构的复杂嵌套查询,但它总是让人觉得笨重。
答案 1 :(得分:2)
也许我不明白,但列表理解有什么问题?你的第二个例子变成了:
[(x,y,z) | x <- xs, y <- xs, z <- xs
, x /= y && y /= z && x /= z
, (p1 x y z) == (p2 x y z)]
这允许你返回值;要检查公式是否满足,只需使用null
(由于懒惰,它的评估不会超过需要)。