如果我有一个表示命题逻辑子集的数据类型,例如
data Prop = Lit String
| Neg Prop
| And Prop Prop
| Or Prop Prop
是否有简单的方法在[[Prop]]
上进行通用转换? E.g。
[[And a b, c]]
替换为[[a, b, c]]
[[Or a b, c]]
替换为[[a], [b], [c]]
或Neg a
和a
的子列表的出现,例如将[[Neg a, x, a], [b]]
转入[[b]]
这感觉就像接近例如uniplate确实如此,但“升级两级”。
答案 0 :(得分:1)
我认为你的第二条规则是错误的,你真的应该说:
[[Or a b],[c]]
替换为[[a],[b],[c]]
或者:
[[Or a b, c]]
替换为[[a,c],[b,c]]
换句话说,我假设您正在尝试将Prop
转换为替代代表[[Prop]]
,其中第一级列表是"或"第二级列表是"和" s,所有术语都是文字或Neg
- 文字。因此,您试图想象如何应用一堆通用结构规则来进行转换,如:
[[And a (Or b c)]]
[[a, Or b c]] -- apply "And" rule
[[a,b],[a,c]] -- apply some kind of "Or" distribution rule
如果是这样,通用转换并没有多大用处。使用当前的数据类型,您只能将这些转换应用于顶级表达式。例如,此处没有明显的方法来应用Or
规则:
[[And a (And b (Or c d))]]
没有首先应用And
规则几次。如果您更改数据类型以添加L2 [[Prop]]
构造函数,那么您可以将上面的表达式转换为:
[[And a (And b (L2 [[c],[d]]))]] -- apply "Or" rule
它不清楚是什么让你买。
最终,我不认为这是正确的做法......
您对Prop
数据类型中的介词逻辑有完全充分的表示;你有一个理想的最终代表。不是尝试使用零碎的通用转换将Prop
表示转换为最终表示,而是使用标准的递归Prop-to-Prop转换将Prop
表示转换为规范Prop
形式,并且翻译作为最后一步。
这里,一个合理的规范形式是:
Or e1 (Or e2 (... (Or e3 e4)))
每个ek
的形式为:
And t1 (And t2 (... (And t3 t4)))
并且每个tk
都是Lit _
或Neg (Lit _)
。显然,这个规范形式可以很容易地转换为[[Prop]]
所需的最终表示。
我在下面提供了一个可能的解决方案。我没有看到通过泛型转换简化事物的机会。大多数模式匹配似乎都在进行非平凡的工作。
经过一些序言:
import Data.List
data Prop = Lit String
| Neg Prop
| And Prop Prop
| Or Prop Prop
deriving (Eq)
然后,将任意Prop
转换为此规范形式的一种方法是首先将所有Neg
向下推到字面值:
pushNeg :: Prop -> Prop
pushNeg = push False
where
-- de Morgan's laws
push neg (And x y) = (if neg then Or else And) (push neg x) (push neg y)
push neg (Or x y) = (if neg then And else Or) (push neg x) (push neg y)
-- handle Neg and Lit
push neg (Neg y) = push (not neg) y
push neg (Lit l) = if neg then Neg (Lit l) else Lit l
然后将所有And
向下推到它们之上。这样做是很难的,但我认为以下是正确的,即使它在某些情况下做了一些不必要的工作:
pushAnd :: Prop -> Prop
pushAnd (Or x y) = Or (pushAnd x) (pushAnd y)
pushAnd (And x y)
= let x' = pushAnd x
in case x' of
Or u v -> Or (pushAnd (And u y)) (pushAnd (And v y))
_ -> let y' = pushAnd y
in case y' of
Or u v -> Or (pushAnd (And x' u)) (pushAnd (And x' v))
_ -> And x' y'
pushAnd x = x
然后以递归方式将所有And
和Or
子句设为右关联:
rassoc :: Prop -> Prop
rassoc (Or (Or x y) z) = rassoc (Or x (Or y z))
rassoc (Or x z) = Or (rassoc x) (rassoc z)
rassoc (And (And x y) z) = rassoc (And x (And y z))
rassoc (And x z) = And x (rassoc z)
rassoc x = x
最后将规范表单转换为最终表示形式(删除不一致的条款和重复的条款,而我们在其中):
translate :: Prop -> [[Prop]]
translate = nub . map nub . filter consistent . doOr
where
doOr x = case x of
Or x y -> doAnd x : doOr y
x -> doAnd x : []
doAnd x = case x of
And x y -> x : doAnd y
x -> x : []
consistent lits =
let (falses, trues) = partition isNeg lits
falses' = map (\(Neg (Lit l)) -> l) falses
trues' = map (\ (Lit l) -> l) trues
in null (intersect falses' trues')
isNeg (Neg x) = True
isNeg _ = False
整个管道是:
final :: Prop -> [[Prop]]
final = translate . rassoc . pushAnd . pushNeg
以及一些测试代码:
a = Lit "a"
b = Lit "b"
c = Lit "c"
d = Lit "d"
e = Lit "e"
-- Show instance, but only for `final` forms
instance Show Prop where
show (Lit x) = x
show (Neg (Lit x)) = '~':x
main :: IO ()
main = do print $ final (Neg a)
print $ final (Or a b)
print $ final (Or a a)
print $ final (And a b)
print $ final (And (Or (And (Or a b) c) d) e)
print $ final (And (Or (Or a b) c) (Neg (And a (Or b d))))
输出:
[[~a]]
[[a],[b]]
[[a]]
[[a,b]]
[[a,c,e],[b,c,e],[d,e]]
[[a,~b,~d],[b,~a],[c,~a],[c,~b,~d]]
还有一些进一步简化的机会,如:
final (And a (Or a b))
提供最终表单[[a],[a,b]]
,而不只是[[a]]
。