我刚刚从typeclassopedia读了Monad和Applicative之间的区别。 我可以理解,没有join Applicative 。 但是下面的描述对我来说看起来含糊不清,而我无法弄清楚单子计算/行为的“结果”到底是什么意思。 所以,如果我把一个值写入Maybe ,这会产生一个monad,这个“计算”的结果是什么? 让我们仔细看看(>> =)的types。 基本的直觉是它将两个计算结合到一个更大的计算中。 第一个参数ma是第一个计算。 然而,如果第二个论点只是一个mb,那将是无聊的; 那么计算就不可能互相交互(实际上,这正是Applicative的情况)。 因此,(>> =)的第二个参数具有typesa – > mb:这种types的函数在给定第一个计算结果的情况下可以产生第二个要运行的计算。 …直观地说,正是这种能力使用以前的计算输出来决定接下来运行哪些计算,使得Monad比Applicative更强大。 应用计算的结构是固定的,而Monad计算的结构可以基于中间结果而改变。 是否有一个具体的例子说明“能够使用先前计算的输出来决定接下来要运行什么计算”,Applicative没有?
鉴于: Applicative m, Monad m => mf :: m (a -> b), ma :: ma 这似乎被认为是一个法律: mf <*> ma === do { f <- mf; a <- ma; return (fa) } 或者更简洁: (<*>) === ap Control.Applicative的文档说<*>是“顺序应用程序”,这表明(<*>) = ap 。 这意味着, <*>必须按顺序从左到右评估效果,与>>= …保持一致。但这种感觉是错误的。 McBride和Paterson的原始文件似乎意味着从左到右的sorting是任意的: IO monad,实际上任何Monad都可以通过使用pure = return和<*> = ap 。 我们也可以用相反顺序执行计算的ap的变体 ,但是在本文中我们应该保持从左到右的顺序。 所以有两个合法的,不重要的派生出现在<*> >>=和return ,具有不同的行为。 […]
我已经提到IO不符合单子法,但是我没有find一个简单的例子来表明这一点。 有人知道一个例子吗? 谢谢。 编辑:正如ertes和nm指出的,使用seq有点不合法,因为它可以使任何monad失败的法律(结合undefined )。 由于undefined可能被视为非终止计算,所以使用它是完全正确的。 所以修改后的问题是: 有人知道一个例子,说明IO不能满足单子法则,不使用seq ? (或者,如果seq不被允许,那么certificateIO确实符合法律?)
我学习Haskell的方式我已经开始掌握monad概念,并开始使用我的代码中已知的monad,但是从devise者的angular度来看,我仍然遇到困难。 在面向对象中有几个规则,比如“为名称标识名词”,注意某种状态和接口……但是我无法为monadfind相应的资源。 那么如何将自然界中的一个问题看成一元问题呢? 一元devise有什么好的devise模式? 当你意识到某些代码可以更好地重构为monad时,你的方法是什么?
我正在实施Haskell中的UCTalgorithm,这需要相当数量的数据杂耍。 没有太多的细节,这是一个模拟algorithm,在每个“步骤”中,根据一些统计属性selectsearch树中的叶节点,在该叶构build新的子节点,并且与新叶和所有的祖先更新。 考虑到所有这些杂耍,我并不十分清楚如何让整个search树成为一个不可变的数据结构。 相反,我一直在玩ST monad,创build由可变STRef组成的结构。 一个人为的例子(与UCT无关): import Control.Monad import Control.Monad.ST import Data.STRef data STRefPair sab = STRefPair { left :: STRef sa, right :: STRef sb } mkStRefPair :: a -> b -> ST s (STRefPair sab) mkStRefPair ab = do a' <- newSTRef a b' <- newSTRef b return $ STRefPair a' b' derp […]
我对这三个概念非常困惑。 有没有简单的例子来说明Category,Monoid和Monad之间的区别? 如果有这些抽象概念的例证,这将是非常有帮助的。
上帝我讨厌“代码味道”这个词,但我想不出更准确的东西。 在空闲时间,我正在devise一个高级语言和编译器,以便学习编译器构造,语言devise和函数式编程(编译器正在用Haskell编写)。 在编译器的代码生成阶段,我必须在遍历语法树时维护“状态”数据。 例如,编译stream程控制语句时,我需要为要跳转的标签生成唯一的名称(从传入,更新和返回的计数器生成的标签,并且计数器的旧值不能再次使用)。 另一个例子是当我在语法树中遇到内联string文字时,他们需要永久转换成堆variables(在空白string中最好存储在堆中)。 我目前正在包装整个代码生成模块在状态monad来处理这个。 我被告知编写一个编译器是一个非常适合于function范例的问题,但是我发现我的devise方式与C中的devise方式非常相似(你可以用任何语言编写C语言 – 甚至Haskell w /状态monads)。 我想学习如何在Haskell中思考(而不是在函数范式中) – 而不是在Haskell语法中使用C语言。 我应该真的试图消除/最小化使用状态monad,还是它是一个合法的function“devise模式”?
Monads可以做许多惊人的,疯狂的事情。 他们可以创buildvariables来保存值的叠加。 在计算之前,它们可以让您访问未来的数据。 他们可以让你写破坏性的更新,但不是真的。 然后继续monad让你打破人心! 通常你自己的。 😉 但是,这是一个挑战:你能制造一个可以暂停的monad吗? 数据暂停sx 实例Monad(暂停) mutate ::(s – > s) – >暂停s() yield :: Pause s() step :: s – > Pause s() – >(s,Maybe(Pause s())) Pause monad是一种状态monad(因此mutate ,明显的语义)。 通常像这样的monad具有某种“运行”function,它运行计算并将您返回到最终状态。 但Pause是不同的:它提供了一个step函数,它运行计算,直到它调用魔术yield函数。 这里的计算暂停,返回给调用者足够的信息以稍后恢复计算。 对于额外的awesomness:允许调用者修改step之间的状态。 (例如上面的types签名应该允许这样做。) 用例:编写复杂的代码通常很容易,但总的PITA将其转换为在其操作中也输出中间状态。 如果你希望用户能够通过执行中途改变某些事情,事情变得非常复杂。 实施思路: 显然可以通过线程,锁和IO来完成。 但是我们可以做得更好吗? 😉 疯狂的继续单子吗? 也许某种作家monad, yield只是logging当前状态,然后我们可以通过遍历日志中的状态来“伪装”来step它。 (显然,这排除了改变步骤之间的状态,因为现在我们并不真正“暂停”任何东西。)
我一直在阅读有关monad的分类理论。 单子的一个定义使用一对伴随函数。 单子是通过使用这些函数的往返来定义的。 显然附加类在分类理论中是非常重要的,但是我还没有看到Haskell monads在伴随函数方面的任何解释。 有没有人给它一个想法?
我正在48小时内写作自己的计划 (我约85小时),我已经到了关于添加variables和作业的部分。 本章有一个很大的概念上的跳跃,我希望这个过程是分两步完成的,在这之间有一个很好的重构,而不是直接跳到最后的解决scheme。 无论如何… 我已经迷失了许多不同的课程,这些课程似乎有相同的目的: State , ST , IORef和MVar 。 正文中提到了前三个,而最后一个似乎是前三个StackOverflow问题的答案。 它们似乎都在连续调用之间进行状态。 这些都是什么,它们又有什么不同呢? 特别是这些句子没有意义: 相反,我们使用称为状态线程的function,让Haskell为我们pipe理聚合状态。 这让我们可以像处理任何其他编程语言一样使用函数来获取或设置variables。 和 IORef模块允许您使用IO monad内的有状态variables。 所有这些使得行type ENV = IORef [(String, IORef LispVal)]混淆 – 为什么第二个IORef ? 如果我写入type ENV = State [(String, LispVal)]会怎样呢?