Haskell-检查一阶逻辑公式是否已关闭/句子

时间:2018-11-14 15:39:02

标签: haskell

我有一个表示一阶逻辑公式的数据类型声明:

    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)

有什么想法可以对此进行修改吗?

1 个答案:

答案 0 :(得分:3)

这是标准练习。这里有一些提示。

首先,定义一个输出公式的自由变量的函数。

free :: Formula -> Set String

如果愿意,可以使用Set String代替[String]。 为此,请对公式进行归纳。您将需要

  1. 计算两组并集
  2. 从集合中删除变量

您可能需要实现这些操作,或者依赖于标准库(请在欢呼声中查看Data.SetData.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中,我们需要确保pq的绑定变量不相交)。

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)