Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >使用连续monad在“the”(和其他有约束的容器)上构造有效的monad实例

使用连续monad在“the”(和其他有约束的容器)上构造有效的monad实例
EN

Stack Overflow用户
提问于 2012-08-29 09:49:06
回答 4查看 1.7K关注 0票数 31

Set,类似于[],有一个完全定义的一元操作。问题是,它们要求值满足Ord约束,因此不可能在没有任何约束的情况下定义return>>=。同样的问题也适用于需要对可能值进行某种约束的许多其他数据结构。

标准的技巧(在haskell-咖啡馆邮报中建议我这样做)是将Set封装到连续单元中。ContT不在乎底层类型函子是否有任何约束。只有在将Set包装/解包装为连续/从连续性时,才需要约束:

代码语言:javascript
运行
AI代码解释
复制
import Control.Monad.Cont
import Data.Foldable (foldrM)
import Data.Set

setReturn :: a -> Set a
setReturn = singleton

setBind :: (Ord b) => Set a -> (a -> Set b) -> Set b
setBind set f = foldl' (\s -> union s . f) empty set

type SetM r a = ContT r Set a

fromSet :: (Ord r) => Set a -> SetM r a
fromSet = ContT . setBind

toSet :: SetM r r -> Set r
toSet c = runContT c setReturn

这可以根据需要工作。例如,我们可以模拟一个非确定性函数,它要么将其参数增加1,要么保持不变:

代码语言:javascript
运行
AI代码解释
复制
step :: (Ord r) => Int -> SetM r Int
step i = fromSet $ fromList [i, i + 1]

-- repeated application of step:
stepN :: Int -> Int -> Set Int
stepN times start = toSet $ foldrM ($) start (replicate times step)

实际上,stepN 5 0产生了fromList [0,1,2,3,4,5]。如果我们使用[] monad代替,我们将得到

代码语言:javascript
运行
AI代码解释
复制
[0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5]

而不是。

问题是效率。如果我们调用stepN 20 0,输出需要几秒钟,而stepN 30 0没有在合理的时间内完成。结果表明,所有Set.union操作都是在最后执行的,而不是在每次一元计算之后执行。其结果是成倍地构造了许多Set,并且只在最后编写了union,这对于大多数任务来说都是不可接受的。

有什么办法可以绕过它,使这个建筑高效吗?我试过了,但没有成功。

(我甚至怀疑库里-霍华德同构和Glivenko定理可能有一些理论上的限制。Glivenko定理指出,对于任何命题重言式φ,φ公式都可以在直觉逻辑中得到证明。然而,我怀疑证明的长度(以正常形式)可以是指数长的。那么,也许在某些情况下,将计算封装到连续单元中会使其成倍增长?)

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-08-30 06:50:17

Monad是一种特殊的构造和排序计算方法。一个单一的绑定不能神奇地重组你的计算,以便以一种更有效的方式发生。计算的结构有两个问题。

  1. 在评价stepN 20 0时,step 0的计算结果将进行20次计算。这是因为计算的每一步都生成0作为一个备选方案,然后将其输入到下一个步骤,该步骤也生成0作为替代,等等…… 或许这里的回忆录能帮上忙。
  2. 一个更大的问题是ContT对计算结构的影响。通过一些等式推理,扩展了replicate 20 step的结果,定义了foldrM并根据需要进行了多次简化,我们可以看到stepN 20 0相当于: (.(返回0 >>=步骤) >>= .) 此表达式的所有括号都与左侧关联。这很好,因为这意味着每个(>>=)的RHS都是一个基本的计算,即step,而不是一个组合的计算。然而,放大了(>>=)用于ContT的定义, M >>= k= ContT $ \c -> runContT m(a -> runContT (k ) c) 我们看到,当计算一个与左关联的(>>=)链时,每个绑定都会将一个新的计算推到当前的延续c上。为了说明正在发生的事情,我们可以再次使用一些等式推理,扩展(>>=)的定义和runContT的定义,并简化,生成: setReturn 0 setBind (\x1 -> step x1 setBind (\x2 -> step x2 setBind (\x3 -> .)) 现在,对于每个发生的setBind,让我们问自己RHS的论点是什么。对于最左边的情况,RHS参数是setReturn 0之后的整个计算过程。对于第二次出现,这是step x1之后的所有内容,等等。让我们放大到setBind的定义: setBind集f= foldl‘(\s ->并s.( f)空集 在这里,f表示计算的所有其余部分,setBind出现的右侧的所有内容。这意味着,在每一步中,我们都以f的形式捕获计算的其余部分,并尽可能多地应用f,就像set中的元素一样。计算不像以前那样是基本的,而是合成的,这些计算将被重复多次。

问题的症结在于,ContT单体转换器正在将计算的初始结构(您指的是setBind's的左结合链)转换为一个具有不同结构(即右结合链)的计算。这毕竟是非常好的,因为其中一条单数定律说,对于每一个mfg,我们都有这样的计算。

代码语言:javascript
运行
AI代码解释
复制
(m >>= f) >>= g = m >>= (\x -> f x >>= g)

然而,单一法则并没有将复杂性强加于每一个定律方程的每一个侧面。实际上,在这种情况下,构造这个计算的左结合方式是更有效的。setBind's的左关联链不需要时间计算,因为只有初等子计算是重复的。

事实证明,其他解决方案--将Set压缩为单一产品--也面临着同样的问题。特别是,集单包产生类似的运行时。其原因是,它也将左关联表达式重写为右关联表达式。

我认为您已经把手指放在了一个上,这是非常重要的,但也是相当微妙的问题,坚持Set必须遵守Monad接口。我认为这是无法解决的。问题是单播的绑定类型需要是

代码语言:javascript
运行
AI代码解释
复制
(>>=) :: m a -> (a -> m b) -> m b

ab上都不允许类约束。这意味着我们不能在左边嵌套绑定,除非首先调用monad规则来重写为右关联链。原因如下:给定(m >>= f) >>= g,计算(m >>= f)的类型为m b形式。计算(m >>= f)的值为b类型。但是,由于不能将任何类约束挂在类型变量b上,所以我们无法知道得到的值是否满足Ord约束,因此不能将该值用作我们希望能够计算union的集合的元素。

票数 21
EN

Stack Overflow用户

发布于 2013-05-13 04:36:01

最近在Haskell 奥列格举了一个例子上,如何有效地实现Set单片。引用:

..。然而,有效的真正的集单是可能的。 ..。随函附寄的是有效的正品单套。我是用直接的方式写的(不管怎样,它看起来更快)。关键是尽可能使用优化的选择函数。 {-#语言GADT、TypeSynonymInstances、FlexibleInstances #-}模块SetMonadOpt,其中导入限定的Data.Set作为S导入Control.Monad数据SetMonad a,其中SMOrd ::Ord a => S.Set a -> SetMonad a SMAny :A -> SetMonad a instance Monad SetMonad其中返回x= SMAny x m >>= f= collect。地图f$ toList m toList ::SetMonad a -> a toList (SMOrd x) = S.toList x toList (SMAny x) =x collect ::SetMonad a -> SetMonad a collect [] = SMAny [] collect x=x collect ((SMOrd x):t) = case collect t of SMOrd y -> SMOrd ( SMOrd X y) SMOrd y en21 20#(X (S.fromList y)) collect ((SMAny x):t) = SMOrd y -> SMOrd (S.union y (S.fromList x)) SMAny y -> SMAny (x ++ y) runSet : Ord a => SetMonad a S.Set a runSet (SMOrd x) =x runSet ( x) =x实例en22#其中mzero = SMAny [] mplus (SMAny x) (SMAny y) = SMAny (x ++ y) mplus (SMAny x) (SMOrd y) = SMOrd (S.union y (S.fromList x)) mplus (SMOrd x) (SMAny y) = SMOrd (S.union x (S.fromList y)) mplus (SMOrd x) (SMOrd y) = SMOrd (S.fromList x y)选择:m a m选择= msum。映射返回test1 = runSet (do n1 <-选择1.5 n2 <-选择1.5让n= n1 + n2保护$n<7返回n) -- fromList 2,3,4,5,6 -可从中选择的值可能是高阶的或动作test1‘= runSet (do n1 <- runSet)。映射返回$ 1..5 n2 <- return。映射返回$1.5 n <- liftM2 (+) n1 n2保卫$n<7返回n) -- fromList 2,3,4,5,6 test2 = runSet (我<-选择1.10j <-选择1.10k <-选择1.10警卫$ i*i + j*j == k*k返回(i,j,k)) - fromList (3,4,5),(4,3,5),(6,8,10),(8,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,610) test3 = runSet (我是否<-选择1.10j <-选择1.10k <-选择1.10警卫$ i*i + j*j == k*k返回k) - fromList 5,10 - Petr Pudlak的测试-首先,一般的,非最优的情况步骤::(MonadPlus m) => Int -> Int步骤i=选择i,I+1-在0: stepN ::Int -> S.Set Int stepN = runSet上重复应用step。F其中,f0=返回0fn=f (n-1) >>=步骤--它工作,但显然是指数的{- *SetMonad> stepN 14 fromList 0,1,2,3,4,5,6,7,8,9,10,11,12,13 14 *SetMonad> stepN 15 fromList 0、1、2、3、4、5、6、7、8、9、10、11、12、13、14、15 *SetMonad> stepN 16 fromList 0,1,2,3,4,5,6,7,8,9,10,11,12,13 14,15,16 -} --而现在优化的chooseOrd ::Ord a => a -> a chooseOrd x= SetMonad ( x) ::Int en22# Int #23#i= i,I+1-在0: stepNOpt ::Int -> S.Set Int stepNOpt = runSet上重复应用step。F其中f0=返回0fn=f (n-1) >>= stepOpt {- stepNOpt 14 fromList 0,1,2,3,4,5,6,7,8,9,10,11,12,13 14 stepNOpt 15 fromList 0、1、2、3、4、5、6、7、8、9、10、11、12、13、14、15 stepNOpt 16 fromList 0,1,2,3,4,5,6,7,8,9,10,11,12,13 14,15,16 stepNOpt 30 fromList 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 -}

票数 11
EN

Stack Overflow用户

发布于 2012-08-29 15:29:14

在这种情况下,我不认为您的性能问题是由于使用了Cont

代码语言:javascript
运行
AI代码解释
复制
step' :: Int -> Set Int
step' i = fromList [i,i + 1]

foldrM' f z0 xs = Prelude.foldl f' setReturn xs z0
  where f' k x z = f x z `setBind` k

stepN' :: Int -> Int -> Set Int
stepN' times start = foldrM' ($) start (replicate times step')

获得与基于Cont的实现类似的性能,但完全发生在Set的“受限单”中。

我不确定我是否相信你关于Glivenko定理的说法导致了(规范化)证明大小的指数增长--至少在逐需要的上下文中是这样。这是因为我们可以任意重用子证明(我们的逻辑是二阶的,我们只需要一个forall a. ~~(a \/ ~a)的证明)。证明不是树,而是图(共享)。

通常,您可能会看到Cont包装Set带来的性能成本,但通常可以通过

代码语言:javascript
运行
AI代码解释
复制
smash :: (Ord r, Ord k) => SetM r r -> SetM k r
smash = fromSet . toSet
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12183656

复制
相关文章
object.finalize_object的equals方法
finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。
全栈程序员站长
2022/10/02
6850
object.finalize_object的equals方法
前端基础-HTML(object标签)
object标签 <object type="application/x-shockwave-flash" data="line.swf" width="500" height="500"></obj
cwl_java
2020/04/07
5410
前端基础-HTML(object标签)
java object toarray,Object[] toArray()
java.util.LinkedList.toArray()方法以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。此方法充当基于数组的API和基于集合的API之间的桥梁。
全栈程序员站长
2022/08/28
6610
Object类常用方法
方法签名:public String toString() ① 默认情况下,toString()返回的是“对象的运行时类型 对象的hashCode值(16进制)" ② 在进行String与其它类型数据的连接操作时,自动调用toString()方法
CODER-V
2023/03/04
3550
Object 有啥方法
这个 Object 指的是所有对象的父亲 package java.lang; 下的 object 类
韩旭051
2021/04/14
5870
Object 有啥方法
Java Map的containsKey(Object key)和containsValue(Object value)方法
public void testContainsKeyOrValue(){ Scanner sc = new Scanner(System.in); //Key System.out.println("请输入要查询的学生id:"); String id = sc.next(); System.out.println("你输入的学生id为:"+id+",在学生映射表中是否存在"+ students.con
JavaEdge
2018/05/16
2.1K0
js Object seal方法
接受一个对象作为参数,并返回相同的对象。作为参数传递的对象发生了变化,它现在是一个不接受新属性的对象。不能添加新属性,也不能删除现有属性,但可以更改现有属性。
IT工作者
2022/01/05
3.5K0
Object对象
Object对象是JavaScript中两个顶层对象之一,提供方法供直接调用以及原型链继承调用。
WindRunnerMax
2020/08/27
2.3K0
如何重写object虚方法
在 C# 中 Object 是所有类的基类,所有的结构和类都直接或间接的派生自它。前面这段话可以说所有的 C# 开发人员都知道,但是我相信其中有一部分程序员并不清楚甚至不知道我们常用的 ToString 、 Equals 和 GetHashCode 虚方法都来自于 Object 类,并且我们可以对它们进行重写。重写这三个虚方法可以说在项目开发中经常用到,只不过大部分开发人员并未留意这三个虚方法可以重写,而是自己写方法来实现。 下面我就来具体讲解一下它们三个应该怎么重写。在这里我需要说明的是本篇文章会大量涉及到设计规范和设计要求,代码只是作为辅助理解的形式出现,因此文章中的所有代码将会以代码段的形式出现。
喵叔
2020/09/08
8250
Object.keys和Object.values
使用Object.keys()或者Object.values()获取循环变量,渲染的时候根据循环变量获取值。Object.keys()函数返回索引(不仅仅是数字),Object.values()函数返回值。
从入门到进错门
2018/08/21
5500
"reason":"object mapping for [] tried to parse field [] as object, but found a concrete value"
enclosure_infor这个字段的mapping如下,是个nested类型的:
IT云清
2019/01/22
6.6K0
Java Object 类方法解析
我们都知道 Java 语言是面向对象的编程语言,而面向对象编程以类作为基本单元。我们也都知道,在 Java 中,所有的类都将 Object 类作为父类,而 Object 类本身提供了一些基础但是很有用的方法,这些方法我们在日常工作中经常会用到,因此熟悉它们的原理和用法对我们的开发会有很大的帮助,下面我们来一起看一些这些方法:
指点
2019/01/18
6660
Java Object 类方法解析
面试:Object 方法与原理
clone 方法的用法是对象的浅拷贝和深拷贝,clone是浅拷贝是对基本类型的值传递,对引用类型进行引用类型般的拷贝。深拷贝并拷贝对象的所有属性,并拷贝属性所指向的动态分配内存。实现深拷贝的方法有:1. 重写clone方法,对其内部的引用类型再进行clone. 2.通过序列化实现深拷贝,将拷贝的对象写入内存的字节流中,然后在读出转换为对象。新对象和原对象不存在地址的共享,所以实现深拷贝。3. 可以采用反射来实现深拷贝,迭代的依次拿到字段,并给新对象赋值。
Tim在路上
2020/08/04
3490
Object类
String toString() 返回该对象的字符串表示 返回该对象的字符串表示
默默的成长
2022/11/07
5720
Object类
Object划分
这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这
后端码匠
2021/02/18
7070
Object 有哪些常用方法
Object 是所有类的父类,任何类都默认继承 Object。Object 类到底实现了哪些方法?
Li_XiaoJin
2022/06/10
8030
Object类有哪些方法?
类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
黑洞代码
2021/01/14
1.4K0
Object类有哪些方法?
LINQ to Object
LinQ to Object是指对随意IEnumerable或Ienumerable<T>集合使用linq查询.它可取代查询不论什么可枚举的集合.如List<T>,Array或Dictionary<K,V>.
全栈程序员站长
2022/07/13
1.3K0
LINQ to Object
TypeError: object()
对于上面这个错误,很容易迷惑我们,因为这个错误信息没有很明确的指出,到底是哪段代码除了问题。那这个错误是怎么产生的了,请听我细细道来。
py3study
2020/01/06
1.1K0
点击加载更多

相似问题

bootstrap:未捕获TypeError: Object [object Object]没有方法'tooltip','typeahead‘

40

TypeError: Object [ object ],[object Object]没有方法查找

30

jQuery/ #<Object>:Uncaught #<Object>:Object #<Object>没有“悬停”方法

12

Ajaxui标签:未捕获TypeError: Object [object Object]没有方法' tabs‘

23

Object [Object array]或[Object object]没有方法'then‘

20
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

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

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档