Difference between Monads and Functions

我的梦境 提交于 2019-11-29 15:34:37

It sounds to me like you're discovering the limits of learning by analogy. Monad is precisely defined both as a type class in Haskell and as a algebraic thing in category theory; any comparison using "... like ..." is going to be imprecise and therefore wrong.

So no, since Haskell's monads aren't like functions, since they are 1) implemented as type classes, and 2) intended to be used differently than functions.

This answer is probably unsatisfying; are you looking for intuition? If so, I'd suggest doing lots of examples, and especially reading through LYAH. It's very difficult to get an intuitive understanding of abstract things like monads without having a solid base of examples and experience to fall back on.

Why do we even need monads? This is a good question, and maybe there's more than one question here:

  1. Why do we even need the Monad type class? For the same reason that we need any type class.

  2. Why do we even need the monad concept? Because it's useful. Also, it's not a function, so it can't be replaced by a function. (Your example seems like it does not require a Monad (rather, it needs an Applicative)).

    For example, you can implement context-free parser combinators using the Applicative type class. But try implementing a parser for the language consisting of the same string of symbols twice (separated by a space) without Monad, i.e.:

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

    So that's one thing a monad provides: the ability to use previous results to "decide" what to do. Here's another example:

    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"]
    

Monads (and Functors, and Applicative Functors) can be seen as being about "generalized function application": they all create functions of type f a ⟶ f b where not only the "values inside a context", like types a and b, are involved, but also the "context" -- the same context -- represented by f.

So "normal" function application involves functions of type (a ⟶ b), "generalized" function application is with functions of type (f a ⟶ f b). Such functions can too be composed under normal function composition, because of the more uniform types structure: f a ⟶ f b ; f b ⟶ f c ==> f a ⟶ f c.

Each of the three creates them in a different way though, starting from different things:

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)

In practice, the difference is in how do we get to use the resulting value-in-context type, seen as denoting some type of computations.

Writing in generalized do notation,

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

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:

And their types,

"liftF1"   :: (Functor     f) => (a ⟶ b)      ⟶ f a ⟶       f b           -- fmap

liftA2     :: (Applicative f) => (a ⟶ b ⟶ c) ⟶ f a ⟶       f b  ⟶ f c

"liftBind" :: (Monad       f) => (a ⟶ b ⟶ c) ⟶ f a ⟶ (a ⟶ f b) ⟶ f c
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!