Monad和函数之间的区别

时间:2014-04-23 14:02:23

标签: function functional-programming monads

好的,关于 Monad ,我知道有足够的问题被问到了。我并不想打扰任何人再次询问什么是monad

实际上,我读过What is a monad?,这非常有帮助。我觉得我非常接近真正理解它。

我在这里创建这个问题只是为了描述我对Monad和Function的一些看法,并希望有人能够纠正我或确认它是正确的。


该帖子中的一些答案让我觉得 monad 有点像 function

Monad接受一个类型,返回一个包装类型(return),它也可以采用一种类型,对它进行一些操作并返回一个包装类型(bind)。

从我的角度来看,它有点像 function 。一个函数需要一些东西并做一些操作并返回一些东西。

那么为什么我们甚至需要monad ?我认为其中一个关键原因是monad为初始数据/类型的顺序操作提供了更好的方法或模式。

例如,我们有一个初始整数i。在我们的代码中,我们需要逐步应用10个函数f1, f2, f3, f4, ..., f10,即我们首先在f1上应用i,获取结果,然后对其应用f2结果,然后我们得到一个新结果,然后应用f3 ...

我们可以通过函数原始执行此操作,就像f1 i |> f2 |> f3...一样。但是,步骤中的中间结果不一致;此外,如果我们必须在中间的某个地方处理可能的失败,事情会变得很难看。如果我们不希望整个过程在异常上失败,那么无论如何都必须构造Option。很自然地,monad进来了。

Monad统一并强制所有步骤中的返回类型。这大大简化了代码的逻辑和可读性(这也是design patterns的目的,不是这样)。此外,它更容易防止错误或错误。例如,Option Monad强制每个中间结果为options,并且很容易实现fast fail范例。

就像monad描述的很多帖子一样,monad是一种设计模式,是一种更好的方法,可以将功能/步骤结合起来构建流程。


我理解正确吗?

2 个答案:

答案 0 :(得分:1)

听起来像你通过类比发现了学习的极限。 Monad被精确地定义为Haskell中的类型类和类别理论中的代数类;任何比较使用" ...喜欢......"将是不精确的,因此是错误的。

所以不,因为Haskell的monad不像函数,因为它们1)实现为类型类,2)打算使用不同于函数。

这个答案可能不尽如人意;你在寻找直觉吗?如果是这样,我建议做很多例子,尤其是阅读LYAH。很难直观地理解像monads这样的抽象事物而没有扎实的实例和经验基础。

为什么我们甚至需要monad?这是一个很好的问题,也许这里有不止一个问题:

  1. 为什么我们甚至需要Monad类型?出于同样的原因我们需要任何类型类。

  2. 为什么我们甚至需要monad概念?因为它很有用。此外,它不是一个功能,因此它不能被一个功能所取代。 (你的例子似乎需要一个Monad(相反,它需要一个Applicative))。

    例如,您可以使用Applicative类型类实现无上下文解析器组合器。但是尝试在没有Monad的情况下为由相同的符号串组成的语言(由空格分隔)实现一个解析器,即:

    a a   -> yes
    a b   -> no
    ab ab -> yes
    ab ba -> no
    

    这是monad提供的一件事:能够使用以前的结果来决定""决定"该怎么办。这是另一个例子:

    f :: Monad m => m Int -> m [Char]
    f m = 
        m >>= \x -> 
        if x > 2 
            then return (replicate x 'a') 
            else return []
    
    f (Just 1)  -->>  Just ""
    f (Just 3)  -->>  Just "aaa"
    f [1,2,3,4] -->>  ["", "", "aaa", "aaaa"]
    

答案 1 :(得分:0)

Monads (以及 Functors Applicative Functors )可以看作是关于“ 广义”功能应用的”:它们都创建类型为 f a ⟶ f b 的函数,其中不仅是“上下文中的值”,例如类型为 a { {1}} ,但也涉及由 b 表示的“上下文”(即相同的上下文)。

因此“普通”功能应用程序涉及类型为 f 的功能,“通用”功能应用程序具有类型为 (a ⟶ b) 的功能。由于更统一的类型结构: (f a ⟶ f b)

三个 的每一个都以不同的方式创建它们,从不同的事物开始

f a ⟶ f b  ;  f b ⟶ f c  ==>  f a ⟶ f c

实际上,区别在于我们如何使用所产生的上下文中值类型,这被视为表示某种类型的计算

以广义Functors: fmap :: Functor f => (a ⟶ b) ⟶ (f a ⟶ f b) Applicative Functors: (<*>) :: Applicative f => f (a ⟶ b) ⟶ (f a ⟶ f b) Monadic Functors: (=<<) :: Monad f => (a ⟶ f b) ⟶ (f a ⟶ f b)书写方式

do

及其类型,

Functors:      do { x <- a ;            return (g x)   }    g <$> a

Applicative    do { x <- a ; y <- b   ; return (g x y) }    g <$> a <*> b
 Functors:                                                  (\ x -> g x <$> b  ) =<< a

Monadic        do { x <- a ; y <- k x ; return (g x y) }    (\ x -> g x <$> k x) =<< a
 Functors: