我有一个表示一阶逻辑公式的数据类型声明:
data Term = Var String
| Fun String [Term]
deriving (Eq, Show, Read)
data Formula = Pred String [Term]
| Equal Term Term
| Not Formula
| And Formula Formula
| Or Formula Formula
| Implies Formula Formula
| Exists String Formula
| Forall String Formula
deriving (Eq, Show, Read)
现在如何定义一个返回布尔值的函数,该函数检查给定的公式是否闭合(一个句子)?在封闭公式中,没有自由变量,每个量化的变量(用∃或defined定义)在其子公式中仅量化一次。
编辑: 谢谢您的指示,我想我现在已经完全掌握了您的描述,并提供了公式的自由变量列表。问题出在第二部分,每个变量如果被量化,只能被量化一次。
例如公式
formula :: Formula
formula = Exists "X" (Exists "X" (Equal (Fun "c" []) (Fun "c" [])))
没有可用变量,因此我的函数返回True
,但是"X"
两次定义了∃
,因此它应该无效。公式∃Xφ或∀Xφ不应包含任何子公式∃Xψ或∀Xψ。
获取定义了存在量词的自由变量的函数部分看起来像这样
varFree (Exists x y) = filter (/= x) (varFree y)
varFree (Forall x y) = filter (/= x) (varFree y)
有什么想法可以对此进行修改吗?
答案 0 :(得分:3)
这是标准练习。这里有一些提示。
首先,定义一个输出公式的自由变量的函数。
free :: Formula -> Set String
如果愿意,可以使用Set String
代替[String]
。
为此,请对公式进行归纳。您将需要
您可能需要实现这些操作,或者依赖于标准库(请在欢呼声中查看Data.Set
和Data.List
)。
然后,要检查公式是否已关闭,您可以简单地使用null (free formula)
并获取所需的布尔值。
要实现“每个变量只能被量化一次”这一部分,则以递归方式进行定义更方便
freeBound :: Formula -> Maybe ([String], [String])
同时计算公式的自由变量和绑定变量。当找到重复的绑定变量时,我们返回Nothing
,将公式标记为无效。
例如,我们需要
freeBound (Exists "X" (Equal (Fun "c" []) (Fun "c" [])))
= Just ([], ["X"])
freeBound (Exists "X" (Exists "X" (Equal (Fun "c" []) (Fun "c" []))))
= Nothing
要实现此目的,我们可能需要一些“成员资格”测试(elem
,以检查是否没有第二次量化)和一些“脱节”测试(例如,在And p q
中,我们需要确保p
和q
的绑定变量不相交)。
Maybe
包装器可能有点烦人,但是可以通过使用单子或辅助助手来减轻这种负担。例如
freeBound (And p q) = do
(freeP, boundP) <- freeBound p
(freeQ, boundQ) <- freeBound q
guard (disjoint boundP boundQ)
return (freeP `union` freeQ, boundP `union` boundQ)