我一直在使用以下数据结构来表示Haskell中的命题逻辑:
data Prop
= Pred String
| Not Prop
| And Prop Prop
| Or Prop Prop
| Impl Prop Prop
| Equiv Prop Prop
deriving (Eq, Ord)
欢迎对此结构发表任何评论。
但是,现在我想扩展我的算法来处理FOL - 谓词逻辑。 什么是在Haskell中表示FOL的好方法?
我见过的版本 - 几乎是 - 上面的扩展,以及基于更经典的无上下文语法的版本。有没有关于此的文献,可以推荐吗?
答案 0 :(得分:29)
这称为higher-order abstract syntax。
第一个解决方案:使用Haskell的lambda。 数据类型可能如下所示:
data Prop
= Not Prop
| And Prop Prop
| Or Prop Prop
| Impl Prop Prop
| Equiv Prop Prop
| Equals Obj Obj
| ForAll (Obj -> Prop)
| Exists (Obj -> Prop)
deriving (Eq, Ord)
data Obj
= Num Integer
| Add Obj Obj
| Mul Obj Obj
deriving (Eq, Ord)
您可以将公式编写为:
ForAll (\x -> Exists (\y -> Equals (Add x y) (Mul x y))))
The Monad Reader文章对此进行了详细介绍。强烈推荐。
第二个解决方案:
使用
之类的字符串data Prop
= Not Prop
| And Prop Prop
| Or Prop Prop
| Impl Prop Prop
| Equiv Prop Prop
| Equals Obj Obj
| ForAll String Prop
| Exists String Prop
deriving (Eq, Ord)
data Obj
= Num Integer
| Var String
| Add Obj Obj
| Mul Obj Obj
deriving (Eq, Ord)
然后你可以写一个像
这样的公式ForAll "x" (Exists "y" (Equals (Add (Var "x") (Var "y")))
(Mul (Var "x") (Var "y"))))))
优点是您可以轻松地显示公式(很难显示Obj -> Prop
函数)。缺点是你必须在碰撞(~α转换)和替换(~β转换)上写更改名称。在这两种解决方案中,您都可以使用GADT而不是两种数据类型:
data FOL a where
True :: FOL Bool
False :: FOL Bool
Not :: FOL Bool -> FOL Bool
And :: FOL Bool -> FOL Bool -> FOL Bool
...
-- first solution
Exists :: (FOL Integer -> FOL Bool) -> FOL Bool
ForAll :: (FOL Integer -> FOL Bool) -> FOL Bool
-- second solution
Exists :: String -> FOL Bool -> FOL Bool
ForAll :: String -> FOL Bool -> FOL Bool
Var :: String -> FOL Integer
-- operations in the universe
Num :: Integer -> FOL Integer
Add :: FOL Integer -> FOL Integer -> FOL Integer
...
第三种解决方案:使用数字表示变量绑定的位置,其中lower表示更深。例如,在ForAll(Exists(Equals(Num 0)(Num 1)))中,第一个变量将绑定到Exists,第二个变量将绑定到ForAll。这被称为de Bruijn数字。请参阅I am not a number - I am a free variable。
答案 1 :(得分:4)
在这里添加一个答案似乎很合适,提到功能珍珠Using Circular Programs for Higher-Order Syntax,由Axelsson和Claessen在ICFP 2013上展示,briefly described by Chiusano on his blog。
这个解决方案巧妙地结合了Haskell语法(@ sdcvvc的第一个解决方案)的巧妙使用和轻松打印公式的能力(@ sdcvvc'第二个解决方案)。
forAll :: (Prop -> Prop) -> Prop
forAll f = ForAll n body
where body = f (Var n)
n = maxBV body + 1
bot :: Name
bot = 0
-- Computes the maximum bound variable in the given expression
maxBV :: Prop -> Name
maxBV (Var _ ) = bot
maxBV (App f a) = maxBV f `max` maxBV a
maxBV (Lam n _) = n
此解决方案将使用数据类型,例如:
data Prop
= Pred String [Name]
| Not Prop
| And Prop Prop
| Or Prop Prop
| Impl Prop Prop
| Equiv Prop Prop
| ForAll Name Prop
deriving (Eq, Ord)
但允许您将公式编写为:
forAll (\x -> Pred "P" [x] `Impl` Pred "Q" [x])