Why do monads not compose when a Monad is an Applicative and an Applicative is a Functor. You see this inheritance chain in many articles on the web ( Which i have gone through ). But when Functors and Applicatives compose why do Monads break this ?
Can someone provide a simple example in scala which demonstrates this issue ? I know this is asked a lot but kind of hard to understand without a simple example.
First, let's start with a simple problem. Let's say, we need to get a sum of two integers, each wrapped in both Future and Option. Let's take cats library in order to resemble Haskell’s standard library definitions with Scala-syntax.
If we use monad approach (aka flatMap), we need:
both Future and Option should have Monad instances defined over them
we also need monadic transformer OptionT which will work only for Option (precisely F[Option[T]])
So, here is the code (let's forget about for-comprehension and lifting to make it simpler):
val fa = OptionT[Future, Int](Future(Some(1)))
val fb = OptionT[Future, Int](Future(Some(2)))
fa.flatMap(a => fb.map(b => a + b)) //note that a and b are already Int's not Future's
if you look at OptionT.flatMap sources:
def flatMap[B](f: A => OptionT[F, B])(implicit F: Monad[F]): OptionT[F, B] =
flatMapF(a => f(a).value)
def flatMapF[B](f: A => F[Option[B]])(implicit F: Monad[F]): OptionT[F, B] =
OptionT(F.flatMap(value)(_.fold(F.pure[Option[B]](None))(f)))
You'll notice that the code is pretty specific to Option's internal logic and structure (fold, None). Same problem for EitherT, StateT etc.
Important thing here is that there is no FutureT defined in cats, so you can compose Future[Option[T]], but can't do that with Option[Future[T]] (later I'll show that this problem is even more generic).
On the other hand, if you choose composition using Applicative, you'll have to meet only one requirement:
both Future and Option should have Applicative instances defined over them
You don't need any special transformers for Option, basically cats library provides Nested class that works for any Applicative (let's forget about applicative builder's sugar to simplify understanding):
val fa = Nested[Future, Option, Int](Future(Some(1)))
val fb = Nested[Future, Option, Int](Future(Some(1)))
fa.map(x => (y: Int) => y + x).ap(fb)
Let's swap Option and Future:
val fa = Nested[Option, Future, Int](Some(Future(1)))
val fb = Nested[Option, Future, Int](Some(Future(1)))
fa.map(x => (y: Int) => y + x).ap(fb)
Works!
So yes Monad is Applicative, Option[Future[T]] is still a monad (on Future[T] but not on T itself) but it allows you to operate only with Future[T] not T. In order to "merge" Option with Future layers - you have to define monadic transformer FutureT, in order to merge Future with Option - you have to define OptionT. And, OptionT is defined in cats/scalaz, but not FutureT.
In general (from here):
Unfortunately, our real goal, composition of monads, is rather more
difficult. .. In fact, we can actually prove that, in a certain sense,
there is no way to construct a join function with the type above using
only the operations of the two monads (see the appendix for an outline
of the proof). It follows that the only way that we might hope to form
a composition is if there are some additional constructions linking
the two component
And this composition is not even necessary commutative (swappable) as I demonstrated for Option and Future.
As an exercise, you can try to define FutureT's flatMap:
def flatMapF[B](f: A => F[Future[B]])(implicit F: Monad[F]): FutureT[F, B] =
FutureT(F.flatMap(value){ x: Future[A] =>
val r: Future[F[Future[B]] = x.map(f)
//you have to return F[Future[B]] here using only f and F.pure,
//where F can be List, Option whatever
})
basically the problem with such implementation is that you have to "extract" value from r which is impossible here, assuming you can't extract value from Future (there is no comonad defined on it) at least in a "non-blocking" context (like ScalaJs). This basically means that you can't "swap" Future and F, like Future[F[Future[B]] => F[Future[Future[B]. The latter is a natural transformation (morphism between functors), so that explains the first comment on this general answer:
you can compose monads if you can provide a natural transformation swap : N M a -> M N a
Applicatives however don't have such problems - you can easily compose them, but keep in mind that result of composition of two Applicatives may not be a monad (but will always be an applicative). Nested[Future, Option, T] is not a monad on T, regardless that both Option and Future are monads on T. Putting in simple words Nested as a class doesn't have flatMap.
It would be also helpful to read:
http://typelevel.org/cats/tut/applicative.html
http://typelevel.org/cats/tut/apply.html
http://typelevel.org/cats/tut/monad.html
http://typelevel.org/cats/tut/optiont.html
Putting it all together (F and G are monads)
F[G[T]] is a monad on G[T], but not on T
G_TRANSFORMER[F, T] required in order to get a monad on T from F[G[T]].
there is no MEGA_TRANSFORMER[G, F, T] as such transformer can't be build on top of monad - it requires additional operations defined on G (it seems like comonad on G should be enough)
every monad (including G and F) is applicative, but not every applicative is a monad
in theory F[G[T]] is an applicative over both G[T] and T. However scala requires to create NESTED[F, G, T] in order to get composed applicative on T (which is implemented in cats library).
NESTED[F, G, T] is applicative, but not a monad
That means you can compose Future x Option (aka Option[Future[T]]) to one single monad (coz OptionT exists), but you can't compose Option x Future (aka Future[Option[T]]) without knowing that Future is something else besides being a monad (even though they’re inherently applicative functors - applicative is not enough to neither build a monad nor monad transformer on it) . Basically:
OptionT can be seen as non-commutative binary operator defined as OptionT: Monad[Option] x Monad[F] -> OptionT[F, T]; for all Monad[F], T; for some F[T]. Or in general: Merge: Monad[G] x Monad[F] -> Monad[Merge]; for all T, Monad[F]; but only for **some of Monad[G]**, some F[T], G[T];
you can compose any two applicatives into one single applicative Nested: Applicative[F] x Applicative[G] -> Nested[F, G]; for all Applicative[F], Applicative[G], T; for some F[T], G[T],
but you can compose any two monads (inherently functors) only into one applicative (but not into monad).
Tony Morris gave a talk on monad transformers that explains this precise issue very well.
http://tonymorris.github.io/blog/posts/monad-transformers/
He uses haskell, but the examples are easily translatable to scala.
Related
I am trying wrap my head around Semigroupals in Cats. Following are statements from "Scala with Cats" by Underscore.
cats.Semigroupal is a type class that allows us to combine contexts
trait Semigroupal[F[_]] {
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}
The parameters fa and fb are independent of one another: we can compute them in either order before passing them to product. This is in contrast to flatMap, which imposes a strict order on its parameters.
So basically, we should be able to combine two Either contexts as well but that doesn't seem to work:
import cats.instances.either._
type ErrorOr[A] = Either[Vector[String], A]
Semigroupal[ErrorOr].product(Left(Vector("Error 1")), Left(Vector("Error 2")))
// res3: ErrorOr[Tuple2[Nothing, Nothing]] = Left(Vector("Error 1"))
If the USP of semigroupal is to eagerly execute independent operations, both eithers must be evaluated before being passed to product and yet we can't have a combined result.
We might expect product applied to Either to accumulate errors instead of fail fast. Again, perhaps surprisingly, we find that product implements the same fail‐fast behaviour as flatMap.
Isn't it contrary to the original premise of having an alternative approach to be able to combine any contexts of same type?
To ensure consistent semantics, Cats’ Monad (which extends Semigroupal) provides a standard definition of product in terms of map and flatMap.
Why implement product in terms of map and flatMap? What semantics are being referred to here?
So why bother with Semigroupal at all? The answer is that we can create useful data types that have instances of Semigroupal (and Applicative) but not Monad. This frees us to implement product in different ways.
What does this even mean?
Unfortunately, the book doesn't covers these premises in detail! Neither can I find resources online. Could anyone please explain this? TIA.
So basically, we should be able to combine two Either contexts as well but that doesn't seem to work:
It worked, as you can see the result is a valid result, it type checks.
Semigrupal just implies that given an F[A] and a F[B] it produces an F[(A, B)] it doesn't imply that it would be able to evaluate both independently or not; it may, but it may as well not. Contrary to Monad which does imply that it needs to evaluate F[A] before because to evaluate F[B] it needs the A
Isn't it contrary to the original premise of having an alternative approach to be able to combine any contexts of same type?
Is not really a different approach since Monad[F] <: Semigroupal[F], you can always call product on any Monad. Implementing a function in terms of Semigroupal just means that it is open to more types, but it doesn't change the behavior of each type.
Why implement product in terms of map and flatMap? What semantics are being referred to here?
TL;DR; consistency:
// https://github.com/typelevel/cats/blob/54b3c2a06ff4b31f3c5f84692b1a8a3fbe5ad310/laws/src/main/scala/cats/laws/FlatMapLaws.scala#L18
def flatMapConsistentApply[A, B](fa: F[A], fab: F[A => B]): IsEq[F[B]] =
fab.ap(fa) <-> fab.flatMap(f => fa.map(f))
The above laws implies that for any F[A] and for any F[A => B] as long as there exists a Monad (actually FlatMap) for F then, fab.ap(fa) is the same as fab.flatMap(f => fa.map(f))
Now, why? Multiple reasons:
The most common one is the principle of least surprise, if I have a bunch of eithers and I pass them to a generic function, no matter if it requires Monad or Applicative I expect it to fail fast, since that is the behavior of Either.
Liskov, suppose I have two functions f and g, f expects an Applicative and g a Monad, if g calls f under the hood I would expect calling both to return the same result.
Any Monad must be an Applicative, however an accumulating Applicative version of Either requires a Semigroup for the Left, whereas, the Monad instance doesn't require that.
What does this even mean?
It means that we may define another type (for example, Validated) that would only satisfy the Applicative laws but not the Monad laws, as such it can implement an accumulating version of ap
Bonus, since having this situation of having a type that is a Monad but could implement an Applicative that doesn't require sequencing, is so common. The cats maintainers created Parallel to represent that.
So instead of converting your Eithers into Validateds to combine them using mapN you can just use parMapN directly on the Eithers.
Some definition of Monad Transformers in cats.
EitherT[F[_], A, B] is a lightweight wrapper for F[Either[A, B]] that
makes it easy to compose Eithers and Fs together. To use EitherT,
values of Either, F, A, and B are first converted into EitherT, and
the resulting EitherT values are then composed using combinators.
OptionT[F[_], A] is a light wrapper on an F[Option[A]]. Speaking
technically, it is a monad transformer for Option, but you don’t need
to know what that means for it to be useful. OptionT can be more
convenient to work with than using F[Option[A]] directly.
I understand the concept, even saw some interesting talk about it: Monad transformers down to earth by Gabriele Petronella
I understand the Reader Monad, and how Kleisli is just a generalization.
What i do not understand is the statement bellow, that says that it is a monad transformer. What are we stacking exactly ? I don't see 2 monad being stacked here ....
Kleisli can be viewed as the monad transformer for functions. Recall
that at its essence, Kleisli[F, A, B] is just a function A => F[B],
with niceties to make working with the value we actually care about,
the B, easy. Kleisli allows us to take the effects of functions and
have them play nice with the effects of any other F[_].
Any thoughts ?
Monad transformer EitherT[F[_], A, B] (a wrapper for F[Either[A, B]]) appears when we consider composition of two monads: F (outer monad) and Either[A, ?] (inner monad).
Monad transformer OptionT[F[_], A] (a wrapper for F[Option[A]]) appears when we consider composition of two monads: F (outer monad) and Option (inner monad).
Monad transformer Kleisli[F, A, B] (a wrapper for A => F[B]) appears when we consider composition of two monads: A => ? (outer monad) and F (inner monad).
I'm trying to comprehend the idea of free monad, and I'm stumped on the first sentence of cats's docs stating that
A free monad is a construction which allows you to build a monad from
any Functor
My confusion is mainly related to the fact that there is no any functor used\created in the process of "freeing" ADT for KVStoreA. There is no implementation of functor for ADT or something like that. However, documentation for Free[S[_],A] says that S must me a functor:
A free operational monad for some functor S.
Where is that functor that free monad is supposed to be based on?
Thing is, Free monad can be used in a few different ways. In order to use one of them you assume that you have some functor S[_], it will have some Functor[S] defined and you will lift that S[*] to Free[S, *] by allowing some sort of extension to the original S:
Free[S, A] = S[A] or A
This is not valid Scala! They way it is actually implemented is using ADT. This only serves as an explanation of the idea.
This way if you have S[A] and you map it with f: A => B, you would use Functor[S] and receive S[B]. But if you flatMap it with f: A => Free[S, B]... you would still be able to calculate that using Functor[S] and receive S[Free[S, B]]. That's what this code would be be underneath. Remembering that Free[S, A] = S[A] or A you could see that this would turn into S[S[S[...]]] and it could go infinitely nested if not for or A part of Free[S, A] which would let us stop at some point.
Of course we don't calculate it all at once, Free usually uses trampoline to calculate only one thing at a time, so we aren't gonna end with tons of nesting at once.
sealed abstract class Free[S[_], A] extends Product with Serializable {
// ...
}
object Free extends FreeInstances {
/**
* Return from the computation with the given value.
*/
final private[free] case class Pure[S[_], A](a: A) extends Free[S, A]
/** Suspend the computation with the given suspension. */
final private[free] case class Suspend[S[_], A](a: S[A]) extends Free[S, A]
/** Call a subroutine and continue with the given function. */
final private[free] case class FlatMapped[S[_], B, C](c: Free[S, C], f: C => Free[S, B]) extends Free[S, B]
...
}
This trampoline representation implements the same idea as S[A] or A but it allows running computations one step at a time. It also shows that Free[S, *] is S[*] algebra extended by pure and flatMap operations (that assume nothing about S), which justifies calling Free a free algebra.
Actually, until we decide to run the computations we only have lazily evaluated data structure. One way of running it is to call free.run that you have defined for Free in cats - it will use trampoline to evaluate each of this nestings, one at a time, but then it will use Comonad[S] to extract the value - as a result we will get rid of nestings as we go. Comonad[S] is also Functor[S] which is why we don't have to provide it separately to do all these maps.
But that is one way of running things. Another way of running things is just assuming that we are recording the map, flatMap and pure operations using Free. For that we don't have to have Functor[S] at all. We might decide to run things using Comonad[S], but we might also decide something else. What if we translated S[_] to some M[_], but that we knew that this M[_] had a Monad[M]? In this case, we wouldn't have to use Functor[S] at all! We would run translation S ~> M, then, map or flatMap on it, and the S inside of it would be translated using the same S ~> M mechanism. This is what foldMap does - it requires us to provide a natural transformation S ~> M and instance of Monad[M] and Functor[S] is completely unnecessary. While conceptually we can still consider that S as a functor we don't need to rely on any of functors properties, not in the form of Functor[S].
So to finally answer your question - with Free when we are still at the stage of "recording operations" we don't have to assume that S is a functor, so we don't need Functor[S]. When we want to interpret Free[S, A] into something - this is where functor might be actually needed, e.g. if we want to run Free[S, A] into A. But for some interpretations like e.g. foldMap (which is IMHO one of the most popular ones) this is not needed because we treat S as a plain data.
I have been trying simple Monad Transformers where I have for comprehensions involving M[F[A]] where M and F are monads. How can I make M[F[A]] and M[S[A]] work together in a for comp if S is a different monad?
For example:
val a: Future[List[Int]] = ...
val b: Future[Option[Int]] = ...
a requires a ListT[Future, Int] and b requires an OptionT[Future, Int] but these do not compose, do I need to use another transformer? Would this depend on the order I use them in the for comp?
Monad Transformers help you in composing two values of type F[G[X]].
In other terms, monad transformers work with F[G[X]] because they leverage the fact that you know how to compose two G[X] if Monad[G] exists.
Now, in case of F[G[X] and F[H[X]], even if you state that G and H have Monad instances, you still don't have a general way of composing them.
I'm afraid composing F[G[X]] and F[H[X]] has no general solution with monad transformers.
You could try using a monad transformer stack ListT[OptionT[Future, Int]] which combines all effects at once. You can lift a and b into values of that monad transformer stack.
Lets say we have a function
f: (A, A) => A
and we are given two optional values
val x: Option[A] = ...
val y: Option[A] = ...
Now we want to apply the function f to x,y. In case one of the parameters is None, we want to return None. In scalaz we could write
^(x, y)(f)
Now assume that we want to restrict the input parameters for function f by coming up with another function which checks if the parameters meet a constraint. If so the function applies f to its arguments and returns the result wrapped in a Some object. Otherwise it returns None:
fRestricted: (A, A) => Option[A]
The problem now is that we cannot make use of Scalaz anymore, i.e.
^(x, y)(fRestricted)
does not work anymore, since the types are wrong.
Is this actually a common problem? Is there a generic solution for the use case?
It is one of the most basic problems in functional programming (not just Scala).
The thing you were doing with Scalaz was based on applicative functor capabilities of the Option. Unfortunately the standard Scala library does not support applicative functors, however it does support monads, and Option is also a monad. Applicative functors are strictly a more general thing than monads, so whatever applicative functors can do, monads can do too.
Here's how you can exploit the fact that Option is a monad to solve your problem with the standard library:
for {
a <- x
b <- y
c <- fRestricted(a, b)
}
yield c
The syntax above is called a "for-comprehension", and in fact it is nothing more than just a sugar for the following:
x.flatMap( a => y.flatMap( b => fRestricted(a, b) ) )