Can please someone explain the differences between Functor and Monad in the Scala context?
A functor takes a pure function (and a functorial value) whereas a monad takes a Kleisli arrow, i.e. a function that returns a monad (and a monadic value). Hence you can chain two monads and the second monad can depend on the result of the previous one.
Functors apply a function to a wrapped value: Applicatives apply a wrapped function to a wrapped value: Monads apply a function that returns a wrapped value to a wrapped value. Monads have a function >>= (pronounced "bind") to do this.
A Functor is a ubiquitous type class involving types that have one "hole", i.e. types which have the shape F[*] , such as Option , List and Future . (This is in contrast to a type like Int which has no hole, or Tuple2 which has two holes ( Tuple2[*,*] )).
In Scala, Monads is a construction which performs successive calculations. It is an object which covers the other object. It is worth noting that here, the output of an operation at some step is an input to another computations, which is a parent to the recent step of the program stated.
Scala itself really does not emphasize the Functor
and Monad
terms that much. I guess using map
is the functor side, using flatMap
is the Monad side.
For me looking and playing around with scalaz has been so far the best avenue to get a sense of those functional concepts in the scala context (versus the haskell context). Two years ago when I started scala, the scalaz code was gibberish to me, then a few months ago I started looking again and I realized that it's really a clean implementation of that particular style of functional programming.
For instance the Monad
implementation shows that a monad is a pointed functor because it extends the Pointed
trait (as well as the Applicative
trait). I invite you to go look at the code. It has linking in the source itself and it's really easy to follow the links.
So functors are more general. Monads provide additional features. To get a sense of what you can do when you have a functor or when you have a monad, you can look at MA
You'll see utility methods that need an implicit functor (in particular applicative functors) such as sequence
and sometime methods that needs a full monad such as replicateM
.
Taking scalaz as the reference point, a type F[_]
(that is, a type F which is parameterized by some single type) is a functor if a function can be lifted into it. What does this mean:
class Function1W[A, B](self: A => B) { def lift[F[_]: Functor]: F[A] => F[B] }
That is, if I have a function A => B
, a functor F[_]
, then I now have a function F[A] => F[B]
. This is really just the reverse-way of looking at scala's map
method, which (ignoring the CanBuildFrom
stuff) is basically:
F[A] => (A => B) => F[B]
If I have a List of Strings, a function from String to Int, then I can obviously produce a List of Ints. This goes for Option, Stream etc. They are all functors
What I find interesting about this is that you might immediately jump to the (incorrect) conclusion that a Functor is a "container" of A
s. This is an unnecesssary restriction. For example, think about a function X => A
. If I have a function X => A
and a function A => B
then clearly, by composition, I have a function X => B
. But now, look at it this way:
type F[Y] = X => Y //F is fixed in X (X => A) andThen (A => B) is X => B F[A] A => B F[B]
So the type X => A for some fixed X is also a functor. In scalaz, functor is designed as a trait as follows:
trait Functor[F[_]] { def fmap[A, B](fa: F[A], f: A => B): F[B] }
hence the Function1.lift
method above is implemented
def lift[F[_]: Functor]: F[A] => F[B] = (f: F[A]) => implicitly[Functor[F]].fmap(f, self)
A couple of functor instances:
implicit val OptionFunctor = new Functor[Option] { def fmap[A, B](fa: Option[A], f: A => B) = fa map f } implicit def Functor1Functor[X] = new Functor[({type l[a]=X => a})#l] { def fmap[A, B](fa: X => B, f: A => B) = f compose fa }
In scalaz, a monad is designed like this:
trait Monad[M[_]] { def pure[A](a: A): M[A] //given a value, you can lift it into the monad def bind[A, B](ma: M[A], f: A => B): M[B] }
It is not particularly obvious what the usefulness of this might be. It turns out that the answer is "very". I found Daniel Spiewak's Monads are not Metaphors extremely clear in describing why this might be and also Tony Morris's stuff on configuration via the reader monad, a good practical example of what might be meant by writing your program inside a monad.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With