Scala Functor and Monad differences

后端 未结 5 1353
再見小時候
再見小時候 2020-12-22 19:01

Can please someone explain the differences between Functor and Monad in the Scala context?

5条回答
  •  一个人的身影
    2020-12-22 19:22

    A while ago I wrote about that: http://gabrielsw.blogspot.com/2011/08/functors-applicative-functors-and.html (I'm no expert though)

    The first thing to understand is the type ' T[X] ' : It's a kind of "context" (is useful to encode things in types and with this you're "composing" them) But see the other answers :)

    Ok, now you have your types inside a context, say M[A] (A "inside" M), and you have a plain function f:A=>B ... you can't just go ahead and apply it, because the function expects A and you have M[A]. You need some way to "unpack" the content of M, apply the function and "pack" it again. If you have "intimate" knowledge of the internals of M you can do it, if you generalize it in a trait you end with

    trait Functor[T[_]]{
      def fmap[A,B](f:A=>B)(ta:T[A]):T[B]
    }
    

    And that's exactly what a functor is. It transforms a T[A] into a T[B] by applying the function f.

    A Monad is a mythical creature with elusive understanding and multiple metaphors, but I found it pretty easy to understand once you get the applicative functor:

    Functor allow us to apply functions to things in a context. But what if the functions we want to apply are already in a context? (And is pretty easy to end in that situation if you have functions that take more than one parameter).

    Now we need something like a Functor but that also takes functions already in the context and applies them to elements in the context. And that's what the applicative functor is. Here is the signature:

    trait Applicative[T[_]] extends Functor[T]{
      def pure[A](a:A):T[A]
      def <*>[A,B](tf:T[A=>B])(ta:T[A]):T[B]
    }
    

    So far so good. Now comes the monads: what if now you have a function that puts things in the context? It's signature will be g:X=>M[X] ... you can't use a functor because it expects X=>Y so we'll end with M[M[X]], you can't use the applicative functor because is expecting the function already in the context M[X=>Y] .

    So we use a monad, that takes a function X=>M[X] and something already in the context M[A] and applies the function to what's inside the context, packing the result in only one context. The signature is:

    trait Monad[M[_]] extends Applicative[M]{
      def >>=[A,B](ma:M[A])(f:A=>M[B]):M[B]
    }
    

    It can be pretty abstract, but if you think on how to work with "Option" it shows you how to compose functions X=>Option[X]

    EDIT: Forgot the important thing to tie it: the >>= symbol is called bind and is flatMap in Scala. (Also, as a side note, there are some laws that functors, applicatives, and monads have to follow to work properly).

提交回复
热议问题