Aren&#t; t Monads基本上只是"概念"糖?

时间:2015-01-13 15:38:58

标签: haskell monads

假设我们在Haskell中允许两种类型的函数:

  • 严格纯洁(像往常一样)
  • 可能是非纯粹的(程序)

区别将是f.x.通过声明一个点("。")作为函数名的第一个字母,将其声明为非纯函数。

我们还会制定规则:

  • 纯函数可以通过纯函数和非纯函数调用
  • 非纯函数只能由非纯函数调用
  • :可以强制编程非纯函数

有了这种语法糖和手头的规格 - 是否仍然需要Monads?莫纳德可以做哪些规则集不允许的事情吗?

当我开始了解Monads时 - 这正是他们的目的。只有那些非常聪明的人才能通过手边的导管理论工具,通过功能性方法实现这一目标。

3 个答案:

答案 0 :(得分:16)

没有

Monads原则上与纯度或杂质无关。恰好IO模型很好地修改了代码,但Monad类可以完美地用于StateMaybe这样的绝对纯粹的实例。

Monads还允许以非常明确的方式表达复杂的上下文层次结构(因为我选择调用它们)。 "纯/不纯"不是您可能想要做的唯一部门。例如,考虑authorized / unauthorized。可能的用途列表一直在继续...我们建议您查看其他常用的实例,例如STSTMRWS,"限制IO"和朋友们更好地了解可能性。

很快你就会开始制作自己的monad,根据手头的问题量身定做。

答案 1 :(得分:11)

  当我开始了解Monads时 - 这正是他们的目的。

Monads完全具有通用性,与纯度/杂质或命令性测序无关。所以没有,如果我理解你的问题,monad肯定不是效果封装的概念糖。

首先考虑前奏中的绝大多数单子:ListReaderStateContEither(->)与效果或IO无关。假设IO是"规范"这是一个非常普遍的误解。 monad,虽然事实上它确实是一个堕落的案例。

答案 2 :(得分:4)

  当我开始了解Monads时 - 这正是他们的目的。

这:http://homepages.inf.ed.ac.uk/wadler/topics/monads.html#monads是关于Haskell中monad的第一篇论文:

  

分类理论家在20世纪60年代发明了单子理论,以简明扼要地表达普遍代数的某些方面。

所以马上就可以看出monad与“纯”/“不纯”计算无关。最常见的monad(世界上!)是Maybe

data Maybe a
  = Nothing
  | Just a

instance Monad Maybe where
    return = Just
    Nothing >>= f = Nothing
    Just x >>= f = f x

monad是四元组(Maybe, liftM, return, join),其中:

liftM :: (a -> b) -> Maybe a -> Maybe b
liftM f mb = mb >>= return . f

join :: Maybe (Maybe a) -> Maybe a
join Nothing = Nothing
join (Just mb) = mb

请注意,liftM需要Maybe 函数(不是纯粹的!)并将其应用于Maybe,而join需要Maybe两级Just并将其简化为单个图层(因此结果中的Just来自两层join (Just (Just x)) = Just x

Nothing

虽然结果中的Nothing可以来自任一层的join Nothing = Nothing join (Just Nothing) = Nothing

Maybe

)。我们可以将这些术语翻译如下:

  • liftM:可能存在或不存在的值。
  • return:将此函数应用于值(如果存在),否则不执行任何操作。
  • Maybe:获取此值并将其注入join的额外结构。
  • Maybe:取一个(可能存在或不存在的值)可能存在或不存在的值,并删除“可能存在或不存在”这两个层之间的区别。

现在,undef是一种非常合适的数据类型。在脚本语言中,它只是通过使用Nothing或等效来表达Just x来表达,并以与x相同的方式表示t*。在C / C ++中,它通过使用指针类型NULL表示,并允许指针为foreach。在Scala中,有一个明确的容器类型:http://www.scala-lang.org/api/current/index.html#scala.Option。所以你不能说“哦,那只是异常”,因为有异常的语言仍然希望能够在不抛出异常的情况下表达“没有值”,然后在值存在的情况下应用函数(这就是Scala的Option类型的原因)有一个Maybe方法)。但是'如果值在那里'应用此函数'恰恰是>>=的{​​{1}}所做的!所以这是一个非常有用的操作。

您会注意到C和脚本语言通常不允许区分NothingJust Nothing - 值是否存在。在函数式语言中 - 就像Haskell一样 - 允许两个版本都很有意思,这就是为什么我们需要join在我们完成它时才能消除这种区别。 (而且,从数学上讲,用>>=liftM来定义join比用其他方式更好。

顺便提一下,要清除关于Haskell和IO的常见错误概念:GHC的IO实现包装了GHC实现I / O的副作用。即使这是GHC的一个可怕的设计决定---命令式(不同于不纯的!)I / O可以在系统的任何级别上单独建模而不会产生杂质。您不需要副作用(在系统的任何一层)来进行I / O!