首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Haskell:析取范式

Haskell:析取范式
EN

Stack Overflow用户
提问于 2022-10-01 10:44:56
回答 1查看 169关注 0票数 1

我试图创建公式,从逻辑语言到析取范式。到目前为止我所拥有的一切;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
data DNF = Var String| C Bool | Not DNF | And DNF DNF | Or DNF DNF 

toDNF :: DNF -> DNF
dnf (And (Or s1 s2) s3) = Or (And (dnf s1) (dnf s3)) (And (dnf s2) (dnf s3))
dnf (And s1 (Or s2 s3)) = Or (And (dnf s1) (dnf s2)) (And (dnf s1) (dnf s3))

dnf (And s1 s2) = And (dnf s1) (dnf s2)
dnf (Or s1 s2) = Or (dnf s1) (dnf s2)

dnf (Not (Not d)) = dnf d
dnf (Not (And s1 s2)) = Or (Not (dnf s1)) (Not (dnf s2))
dnf (Not (Or s1 s2)) = And (Not (dnf s1)) (Not (dnf s2))

dnf s = s

根据我的理解,我需要导航和,而不是向内,反之亦然,如果有人可以帮助并指出我的缺陷在哪里,这将大大有助于!

EN

回答 1

Stack Overflow用户

发布于 2022-10-01 12:37:17

对于这些类型的问题,很容易陷入特殊的地狱。问题的一部分是,根据一些注释,DNF数据类型太笼统了。在其中一种情况下递归调用dnf s1之后,您实际上完全不知道您在看什么。有许多可用DNF类型表示的潜在有效的DNF“表单”,dnf s1可以是其中的任何一个。这使得很难编写直接的递归操作来处理这些子项。

类型系统可以提供帮助。考虑分离表示输入表达式的类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
data Expr = Var String | C Bool | Not Expr | And Expr Expr | Or Expr Expr

来自表示DNF输出的限制性更强的类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
newtype DNF  = Disj [Conj]             -- DNF is a disjuction
newtype Conj = Conj [Term]             -- of conjunctions
data    Term = JustT VarT | NotT VarT  -- of possibly negated
newtype VarT = VarT String             -- variables

现在,您可以将问题简化为Expr中每个构造函数的一种模式。(不过,正如我们下面将看到的那样,Not的处理方式比其他的要好。)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dnf :: Expr -> DNF
dnf (And s1 s2) = dnfAnd (dnf s1) (dnf s2)
dnf (Or s1 s2)  = dnfOr (dnf s1) (dnf s2)
dnf (Not s1)    = dnfNot (dnf s1)
dnf (C b)       = dnfC b
dnf (Var x)     = dnfVar x

当您编写这些帮助函数之一(比如dnfOr )时,您现在确切地知道了这两个输入是什么样子,以及输出应该是什么样子,这使得其中一些非常琐碎:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dnfOr (Disj conjs1) (Disj conjs2) = Disj (conjs1 ++ conjs2)

这个框架可以提供很高的信心,相信您的最终解决方案将是正确的,并且不会“错过”任何情况,当您使用原始表达式数据类型做所有事情时,这是很难做到的。

如果您需要更多的帮助,下面是一个完整的解决方案。

扰流器跟随

上面的dnfOr函数很简单。一旦您理解了受限的DNF表示,其他的一些也是非常琐碎的:

例如,VarT的情况是该变量的单例连接的单例分离:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dnfVar x = Disj [Conj [JustT (VarT x)]]

对于dnfC,我们可以从DNF中消除布尔常量,方法是使用这样的约定:False是空分离,而True是包含空连接的单例析取。多亏了数学,这些不仅仅是“约定”。它们是可靠和一致的DNF表示,将与递归中的其他术语很好地配合:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dnfC False = Disj []
dnfC True = Disj [Conj []]

现在我们到了“难”的地方。dnfAnd遵循分布规律,导致了新的两两连词的分离。经过一段时间的思考,我把它归结为一条线:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dnfAnd (Disj conjs1) (Disj conjs2) = Disj [c1 ++ c2 | c1 <- conjs1, c2 <- conjs2]

最难的是dnfNot。原来你必须写这样的东西,我不会费心解释的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dnfNot (Disj conjs) = foldr dnfAnd (dnfC True) [conjNot c | c <- conjs]
  where
    conjNot (Conj ts) = Disj [Conj [termNot t] | t <- ts]
    termNot (JustT v) = NotT v
    termNot (NotT v) = JustT v

问题是,Not是使用原始Expr类型最容易解决的一个操作,因为它很容易“向下推”Nots,直到它们都在变量旁边:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
notExpr (And e1 e2) = (Or (notExpr e1) (notExpr e2))
notExpr (Or e1 e2) = (And (notExpr e1) (notExpr e2))
notExpr (Not e1) = e1
notExpr (C b) = C (not b)
notExpr (Var e1) = Not (Var e1)

因此,与其通过首先获得Not的子项DNF,然后否定它,不如将其转换为Expr,然后再将其更改为DNF:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dnf (Not s1) = dnf (notExpr s1)

请注意,此递归将导致无限循环,除非我们添加一个基本情况来处理notExpr在其输出Exprs中生成的一种类型的Expr表达式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-- handle the base case produced by `notExpr`
dnf (Not (Var x)) = Disj [Conj [NotT (VarT x)]]
-- every other occurrence of `Not` gets processed by `notExpr`
dnf (Not s)       = dnf (notExpr s)

完整的代码如下。请注意,我的解决方案在特定情况下会产生不太理想的结果(请参阅main中的最后一个示例)。作为练习,您可能希望尝试修复这个问题,并考虑如何处理从最终解决方案中删除冗余项的更普遍的问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import Data.List

data Expr = Var String | C Bool | Not Expr | And Expr Expr | Or Expr Expr
  deriving (Show)
infixl 3 `And`
infixl 2 `Or`

newtype DNF  = Disj [Conj] deriving (Show)  -- DNF is a disjuction
newtype Conj = Conj [Term] deriving (Show)  -- of conjunctions
data    Term = JustT VarT
             | NotT VarT   deriving (Show)  -- of possibly negated
newtype VarT = VarT String deriving (Show)  -- variables

prettyDNF :: DNF -> String
prettyDNF (Disj conjs)
  = [parens (map prettyTerm ts `sepBy` "∧") | Conj ts <- conjs] `sepBy` "∨"
  where prettyTerm (JustT (VarT x)) = x
        prettyTerm (NotT (VarT x)) = "¬" ++ x

        xs `sepBy` sep = intercalate sep xs
        parens str = "(" ++ str ++ ")"

dnf :: Expr -> DNF

dnf (And s1 s2) = dnfAnd (dnf s1) (dnf s2)
  where
    dnfAnd :: DNF -> DNF -> DNF
    dnfAnd (Disj conjs1) (Disj conjs2) = Disj [Conj (c1 ++ c2) | Conj c1 <- conjs1, Conj c2 <- conjs2]

dnf (Or s1 s2)  = dnfOr (dnf s1) (dnf s2)
  where
    dnfOr :: DNF -> DNF -> DNF
    dnfOr (Disj d1) (Disj d2) = Disj (d1 ++ d2)

dnf (Not (Var x)) = Disj [Conj [NotT (VarT x)]]
dnf (Not s)       = dnf (notExpr s)
  where
    notExpr :: Expr -> Expr
    notExpr (And e1 e2) = (Or (notExpr e1) (notExpr e2))
    notExpr (Or e1 e2) = (And (notExpr e1) (notExpr e2))
    notExpr (Not e1) = e1
    notExpr (C b) = C (not b)
    notExpr (Var e1) = Not (Var e1)

dnf (C b)       = dnfC b
  where
    dnfC :: Bool -> DNF
    dnfC False = Disj []
    dnfC True = Disj [Conj []]

dnf (Var x)     = dnfVar x
  where
    dnfVar :: String -> DNF
    dnfVar x = Disj [Conj [JustT (VarT x)]]

main = mapM_ (putStrLn . prettyDNF . dnf)
  [ (Var "a" `Or` Var "b") `And` (Var "c" `Or` Var "d")
  , Not ((Var "a" `Or` Var "b") `And` (Var "c" `Or` Var "d"))
  , Not (Var "a" `And` Var "b") `Or` (Var "c" `And` Var "d")
  -- This last case prints (a)() which is technically correct
  -- but can be further simplified to (), the singleton
  -- disjunction of an empty conjunction representing "true"
  , Var "a" `Or` C True
  ]
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73920914

复制
相关文章
向DropDownList 下拉框添加新选项[通俗易懂]
大家有没有遇见过这样的情况,假如有一个下拉框,现在让你在下拉框里面添加一个新的选项如“请选择”,而数据库里面又不存在这一选项》要怎么做,下面为大家推荐两种写法:
全栈程序员站长
2022/10/03
2.1K0
向DropDownList 下拉框添加新选项[通俗易懂]
java如何向数组中添加元素[数组的添加]
大家好,我是架构君,一个会写代码吟诗的架构师。今天说一说java如何向数组中添加元素[数组的添加],希望能够帮助大家进步!!!
Java架构师必看
2022/04/06
7.7K0
numpy中np.max和np.maximum
1.np.max(a, axis=None, out=None, keepdims=False)求序列的最值最少接受一个参数axis默认为axis=0即列向,如果axis=1即横向ex:>> np.max([-2, -1, 0, 1, 2])22.np.maximum(X, Y, out=None) X和Y逐位进行比较,选择最大值. 最少接受两个参数ex:>> np.maximum([-3, -2, 0, 1, 2], 0)array([0, 0, 0, 1, 2])
狼啸风云
2019/09/30
1.8K0
向mysql配置文件中添加日志配置
socket = usr/local/lnmp/mysql-5.7.21/mysql.sock
93年的老男孩
2019/12/18
3K0
Python 中如何向列表或数组添加元素
然而,与其它编程语言不同,数组在 Python 中不是一个内置的数据结构。Python 使用列表取代传统的数组。
Python学习者
2023/09/11
3620
numpy中np.column_stack()和np.row_stack()
在numpy库中,对于矩阵的合并操作用两种方法:行合并:np.row_stack()列合并:np.column_stack()具体操作见下面的程序: >>> import numpy as np>>> a=np.arange(16).reshape(4,-1)>>> aarray([[ 0, 1, 2, 3],[ 4, 5, 6, 7],[ 8, 9, 10, 11],[12, 13, 14, 15]])>>> b=np.arange(16,32).reshape(4,-1)>>> barray([[16,
狼啸风云
2021/03/03
1.2K0
【NumPy高级运用】NumPy的Matrix与Broadcast高级运用以及IO操作
Matrix函数的作用是返回给定大小的标识矩阵。 单位矩阵是一个方阵。从左上角到右下角的对角线上的元素(称为主对角线)均为1,其他所有元素均为0。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/c157d43915c24198a13ee8904c348af4.png
上进小菜猪
2022/12/23
5690
【NumPy高级运用】NumPy的Matrix与Broadcast高级运用以及IO操作
向邮件添加附件
可以将附件添加到电子邮件或消息部分(具体地说,是添加到%Net.MailMessagePart或%Net.MailMessage的实例)。要执行此操作,请使用以下方法:
用户7741497
2022/06/09
2.1K0
numpy中np.finfo用法
例子:"""np.finfo使用方法eps是一个很小的非负数除法的分母不能为0的,不然会直接跳出显示错误。使用eps将可能出现的零用eps来替换,这样不会报错。"""import numpy as npx = np.array([1, 2, 3], dtype=float)eps = np.finfo(x.dtype).eps # eps = 2.220446049250313e-16 type = <class 'numpy.float64'>print(eps, type(eps))height = n
狼啸风云
2021/03/03
1.8K0
Python之numpy模块的添加及矩阵乘法的维数问题
在Python中,numpy 模块是需要自己安装的,在安装编程软件时,默认安装了pip,因此我们可以用pip命令来安装
用户7886150
2021/01/27
7730
np.random.rand均匀分布随机数和np.random.randn正态分布随机数函数使用方法
, 可以使用语句sigma * np.random.randn(...) + mu
演化计算与人工智能
2020/08/14
1.8K0
js给数组中对象添加新属性
let person =[{ id: 1, name: 'vhen' },{ id: 2, name: 'json' }] let newArr = obj.map((item,index) =>{ return Object.assign(item,{index:index}) }) 多添加了一些属性,是为了区别字符串单引号和双引号的, 用了.就不用中括号不用单引号 不用点 就要用中括号和单引号 var a =[{name: 'Tom',age:20},{name: 'Tom2'
用户1349575
2022/01/24
20.6K0
python脚本向influxdb写入数
python3使用requests模块向influxdb的http API发送接口请求实现数据写入,如下:
py3study
2020/01/07
1.7K0
numpy中np.array()与np.asarray的区别以及.tolist
array和asarray都可以将结构数据转化为ndarray,但是主要区别就是当数据源是ndarray时,array仍然会copy出一个副本,占用新的内存,但asarray不会。
狼啸风云
2021/03/03
1.2K0
添加新磁盘
1.查看版本 [root@IBOYAA73 ~]# cat /proc/version
陈不成i
2021/05/25
9900
Spring 中的 @Import 注解及向容器中添加 Bean 的几种方式
这次介绍一下 Spring 中的一个重要的注解 @Import 以及向容器中添加 Bean 的几种方式 ,该注解在 SpringBoot 自动转配中起到重要的作用。
wsuo
2020/07/30
1.7K0
np.nanmean, np.nanmax
我们在对一个python numpy数组求均值或最大值的时候,如果这个数组里包含nan,那么程序就会报错或者求出来的值是nan,如下所示
狼啸风云
2021/05/11
5770
spring:如何用代码动态向容器中添加或移除Bean ?
先来看一张类图: 有一个业务接口IFoo,提供了二个实现类:FooA及FooB,默认情况下,FooA使用@Component由Spring自动装配,如果出于某种原因,在运行时需要将IFoo的实现,则F
菩提树下的杨过
2018/01/18
5.2K0
spring:如何用代码动态向容器中添加或移除Bean ?
小程序js添加新对象(读取一维数组数据,动态生成二维对象)
        “https://tx2.a.kwimgs.com/ufile/atlas/NTIxMjM1MzcwMTAyMTA3NjU1NV8xNjY0NTMyMjAxMDkx_0.jpg”,
超级小可爱
2023/02/20
2.5K0
点击加载更多

相似问题

叠加4维np阵列得到5维np阵列

12

三维np阵列中一维np阵列的搜索

14

如何向Numpy数组添加新的维数?

103

从二维阵列形成三维np阵列

24

利用np.einsum向三维阵列各片广播二维阵列行乘法

12
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文