I think I understand what Free monad is. I hope I understand also that functors compose but monads do not, i.e. if M1 and M2 are monads then M1[M2] is not necessarily a monad.
My questions are:
Do Free monads compose ?
Suppose we have functors F1 and F2 and their composition F1[F2]. Suppose also we have Free1 and Free2 -- Free monads for F1 and F2. Can we define a Free monad for F1[F2] with just Free1 and Free2 ?
Hopefully I can answer your question:
Do Free monads compose?
No. For the same reasons as "normal" monads don't. To write monadic bind we need to know something about the underlying monad, or about the underlying functor in a free monad case.
Hopefully the Haskell syntax doesn't scare you too much:
type X f g a = Free f (Free g a)
bind :: X f g a -> (a -> X f g b) -> X f g b
bind (Pure (Pure x)) k = k x
bind (Pure (Free f)) k = error "not implemented"
bind _ = error "we don't even consider other cases"
In the second case we have f :: g (Free g a) and k :: a -> Free f (Free g b). We could fmap, as it's the only thing we can do:
bind (Pure (Free f)) k = let kf = fmap (fmap k) f -- fmapping inside g ∘ Free g
in = error "not implement"
The type of kf will be: g (Free g (Free f (Free g b))), when we'd need Free f (Free g b). You'll arrive at the same problem as when writing a monad instance for any Compose m1 m2, we'd need to reorder "bind layers" from g-g-f-g to f-g-g-g, and to do that commutation we need to know more about f and g.
Please comment, if you want to see the Scala version of above. It will be much more obscure though :(
Can we define a Free monad for F1[F2] with just Free1 and Free2
In other words given:
type Free1[A] = Free[F1, A]
type Free2[A] = Free[F2, B]
type FreeDist[A] = Free1[Free2[A]] = Free[F1, Free[F2, A]]
type FreeComp[A] = Free[F1[F2[_]], A]
Could we write a monad homomorphism (a good mapping) from FreeDist[A] to FreeComp[A]? We can't, for the same reasons as in a previous part.
Scala version
Scalaz has private definitions of subclasses of Free, so I have to implement Free myself to have an "runnable" example. Some of the code scrapped from http://eed3si9n.com/learning-scalaz/Free+Monad.html
First simplest definition of Free in Scala:
import scala.language.higherKinds
trait Functor[F[_]] {
def map[A, B](x: F[A])(f: A => B): F[B]
}
sealed trait Free[F[_], A] {
def map[B](f: A => B)(implicit functor: Functor[F]): Free[F, B]
def flatMap[B](f: A => Free[F, B])(implicit functor: Functor[F]): Free[F, B]
}
case class Pure[F[_], A](x: A) extends Free[F, A] {
def map[B](f: A => B)(implicit functor: Functor[F]): Free[F, B] = Pure[F, B](f(x))
def flatMap[B](f: A => Free[F, B])(implicit functor: Functor[F]): Free[F, B] = f(x)
}
case class Bind[F[_], A](x: F[Free[F, A]]) extends Free[F, A] {
def map[B](f: A => B)(implicit functor: Functor[F]): Free[F, B] = Bind {
functor.map[Free[F,A], Free[F,B]](x) { y => y.map(f) }
}
// omitted
def flatMap[B](f: A => Free[F, B])(implicit functor: Functor[F]): Free[F, B] = ???
}
Using that we can translate the Haskell example into Scala:
type X[F[_], G[_], A] = Free[F, Free[G, A]]
// bind :: X f g a -> (a -> X f g b) -> X f g b
def xFlatMap[F[_], G[_], A, B](x: X[F, G, A], k: A => X[F, G, B])(implicit functorG: Functor[G]): X[F, G, B] =
x match {
case Pure(Pure(y)) => k(y)
case Pure(Bind(f)) => {
// kf :: g (Free g (Free f (Free g b)))
val kf: G[Free[G, Free[F, Free[G, B]]]] = functorG.map(f) { y => y.map(k) }
// But we need Free[F, Free[G, B]]
???
}
// we don't consider other cases
case _ => ???
}
The result is the same, we can't make types match, We'd need transform Free[G, Free[F, A]] into Free[F, Free[G, A]] somehow.
Related
For learning purposes, I am trying to define a wrapper class called DoubleMap which provides the method mapBoth. It essentially takes two functions f and g, where the domain of g is the co-domain of f. The composition of this function (g o f) should then be mapped of the container wrapped by DoubleMap
This is my current code:
implicit class DoubleMap
[A, B, C, F[X] <: List[X]] // just List for now
(xs: F[A])(implicit cbf: CanBuildFrom[F[A], C, F[C]]) {
def mapBoth(f: A => B)(g: B => C): F[C] =
xs.map(f andThen g).to[F]
}
However, when I want to use the method like this:
List(true, false, false).mapBoth(!_)(!_)
I get a cryptical error message about the type mismatch between the (found) type CanBuildFrom[List[_], Nothing, List[Nothing]] and the (required) type CanBuildFrom[List[Boolean], C, List[C]]
Why does the compiler infer the first type?
Your call expands to
DoubleMap(xs).mapBoth(!_)(!_)
so all of DoubleMap's type parameters and cbf need to be inferred before the mapBoth call is handled. To fix it, just move these parameters to mapBoth:
implicit class DoubleMap
[A, F[X] <: List[X]] // just List for now
(xs: F[A]) {
def mapBoth[B, C](f: A => B)(g: B => C)(implicit cbf: CanBuildFrom[F[A], C, F[C]]): F[C] =
xs.map(f andThen g).to[F]
}
Then B and C are determined from f and g, and cbf from F, A and C.
If you wish to not be tied to List, consider Functor from Cats
implicit class DoubleMap[F[_]: Functor, A](xs: F[A]) {
def mapBoth[B, C](f: A => B)(g: B => C): F[C] =
xs.map(f andThen g)
}
or vanilla Scala 2.13 approach (inspired by Luis' 2.12 implementation)
implicit class DoubleMap[F[x] <: IterableOnce[x], A](xs: F[A]) {
def mapBoth[B, C](f: A => B)(g: B => C)(implicit bf: BuildFrom[F[A], C, F[C]]): F[C] =
bf.fromSpecific(xs)(xs.iterator.map(f andThen g))
}
which both output
List(true, false, false).mapBoth(!_)(!_)
Vector(true, false, false).mapBoth(!_)(!_)
res1: List[Boolean] = List(true, false, false)
res2: Vector[Boolean] = Vector(true, false, false)
I've the written the following Haskell function which accepts two monadic values and combine them into a single monadic value (it's just to illustrate the degree of genericity (or generic-ness) that Haskell type-system could support).
combine x y = do
a <- x
b <- y
return (a, b)
and I tested it with three different monads:
main = do
putStrLn $ show $ combine (Just 10) (Just 20) -- Maybe a
putStrLn $ show $ combine [100] [10, 20] -- [] a
a <- combine getLine getLine -- IO a
putStrLn $ show a
And it works great as expected. Now, I want to know if Scala's type-system could allow me to write the above function without compromising the genericity. But I don't know Scala enough (though I wish to explore it). So could anyone help me convert this code into Scala?
I think this is the equivalent:
import cats._
import cats.implicits._
def combine[T, F[_]: Monad](fa: F[T], fb: F[T]) = for {
a <- fa
b <- fb
} yield (a, b)
Where Monad is from a library (cats or scalaz).
combine(Option(10), Option(20)) produces Some((10,20)) and combine(List(100), List(10, 20)) produces List((100,10), (100,20)).
EDIT: The above version is over-constrained, since it requires the two argument types to be the same. def combine[A, B, F[_]: Monad](fa: F[A], fb: F[B]) fixes that.
Your combine function is equivalent to the Scala code
for { a <- x; b <- y } yield (a,b)
So you might try defining a function:
def combine[M[_],A,B](x: M[A], y: M[B]): M[(A,B)] =
for { a <- x; b <- y } yield (a,b)
And the compiler will complain that flatMap is not a member of M[A] and map is not a member of M[B].
The thing with for is that it is a bit of compiler magic that will accept any type that implements functions called map, flatMap, and withFilter. This is in contrast to Haskell in which we can add (or let the compiler infer) a Monad constraint to let do notation work.
To expand on the answer #JoePallas gave, it is possible to make this work. In fact, the following implementation is essentially how GHC implements typeclasses. The cats and scalaz libraries provide all this stuff for you, but this is how the sausage is made:
First define the interface we need:
trait For[M[_]] {
def map[A,B](ma: M[A], f: A => B): M[B]
def flatMap[A,B](ma: M[A],f: A => M[B]): M[B]
def withFilter[A](ma: M[A],q: A => Boolean): M[A]
}
(I'm using the name For and using a slightly different interface than Monad.)
Then we provide an implicit implementation of this trait for every data type we want to support. Here's an example for Option:
implicit val optionFor = new For[Option] {
def map[A,B](ma: Option[A], f: A => B): Option[B] = ma.map(f)
def flatMap[A,B](ma: Option[A],f: A => Option[B]): Option[B] = ma.flatMap(f)
def withFilter[A](ma: Option[A],q: A => Boolean): Option[A] = ma.withFilter(q).map(a => a)
}
Then we provide an implicit conversion to a type that can apply these operations:
implicit class ForOps[M[_], A](val ma: M[A]) extends AnyVal {
def map[B](f: A => B)(implicit m: For[M]): M[B] = m.map(ma,f)
def flatMap[B](f: A => M[B])(implicit m: For[M]): M[B] = m.flatMap(ma, f)
def withFilter(q: A => Boolean)(implicit m: For[M]): M[A] = m.withFilter(ma,q)
}
And finally, we can define combine:
def combine[M[_]: For, A, B](ma: M[A], mb: M[B]): M[(A, B)] =
for { a <- ma; b <- mb } yield (a, b)
The syntax
def f[T: TC] = ???
is sugar for
def f[T](implicit unutterableName: TC[T]) = ???
An implicit argument list, if not given explicitly at the call site, will be automatically filled in by searching for values/functions with the correct types, as long as those are themselves implicit. In this case, we look for a proof that M is a monad. In the body, this value is implicit, and it has no name to access it. Implicit search can still find it. ForOps allows the 3 for operations to automagically appear on the values by using that Monad.
This is really an explicit version of how GHC implements typeclasses. In the simplest case of no optimization:
class Applicative m => Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
compiles to
data Monad m = Monad {
monadSubApplicative :: Applicative m
return :: forall a. a -> m a
(>>=) :: forall a. m a -> (a -> m b) -> m b
}
and
instance Monad [] where
return = _
(>>=) = _
becomes
monadList :: Monad []
monadList = Monad {
monadSubApplicative = applicativeList
, return = _
, (>>=) = _
}
You will often hear the word "dictionary" be used to describe the underlying data type and values. And combine is
combine :: Monad m -> m a -> m b -> m (a, b)
combine (Monad _ return (>>=)) ma mb = ma >>= \a -> mb >>= \b -> return (a, b)
However, GHC applies a bunch of restrictions to the system that makes it more predictable and performs more optimization. Scala sacrifices this to allow the programmer to perform more interesting acrobatics.
For good measure, an instance like this:
newtype Compose f g a = Compose { unCompose :: f (g a) }
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose fga) = Compose $ fmap (fmap f) fga
would be done like this in Scala (using an implicit def, not a val):
trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] }
final case class Compose[F[_], G[_], A](val get: F[G[A]]) extends AnyVal
object Compose {
// you usually put these implicits in the associated companions
// because implicit search is picky about where it looks
implicit def functor[F[_], G[_]](implicit
functorF: Functor[F],
functorG: Functor[G]
// type lambda: use a type projection on a refinement type
// to create an anonymous type-level function
// it's universally accepted as a horrendous abuse of syntax
// you can use the kind-projector plugin to avoid writing them (directly)
) : Functor[({type L[X] = Compose[F, G, X]})#L]
= new Functor[({type L[X] = Compose[F, G, X]})#L] {
override def map[A, B](cfga: Compose[F, G, A])(f: A => B): Compose[F, G, B] =
Compose(functorF.map(cfga.get) { ga => functorG.map(ga)(f) })
}
}
Making all this stuff explicit is a bit ugly, but it works quite well.
In functional programming (and programming in general) it is good practice to use the least powerful abstraction you can find. In the example you gave, you actually don't need the power of a monad. The combine function is liftA2 from the applicative type class. Example:
import Data.Maybe
import Control.Applicative
z= Just 1
y= Just 2
liftA2 (,) z y
> Just (1,2)
In Scala you have something similar. An example from the Scalaz library which uses the same abstraction:
import scalaz._, Scalaz._
(Option(1) |#| Option(2))(Tuple2.apply)
> res3: Option[(Int, Int)] = Some((1, 2))
The reason you don't need the monad abstraction is that the values are independent of each other.
Consider, you have the Nel of states (Nel stands for NonEmptyList, to make things shorter),
and you want to combine the States to one State, using some function f, for left part of the state and
g for the right part of the state.
So you want something like this:
def foldStatesG[S, A](in: NonEmptyList[State[S, A]])(f: (A, A) => A)(g: (S, S) => S): State[S, A] = {
in.foldLeft1((s1, s2) => State(e => {
val ss1 = s1(e)
val ss2 = s2(e)
g(ss1._1, ss2._1) -> f(ss1._2, ss2._2)
}))
}
I am sure, that I am inventing the bicycle, and such thing already exists, probably in a more general way. But, looking through scalaz I failed to find or recognize it. Would appreciate of any help on this topic.
The second question, describes how I came to such problem. I wanted to make a small simulation, when you have an Enemy (consider it's just a Double), and all possible spells which might hit him Nel[Spell]. So basically I want to generate all possible sequences. For example, if Nel[Spell] = ($, #), then given an enemy E, progression would look like
E -> (), then Nel(E -> $, E -> #), then Nel(E -> $$, E -> ##, E -> $#, E-> #$) etc.. (pseudo code)
Without going too much into details I need something like this:
def combineS(variations: NonEmptyList[Spell]): State[NonEmptyList[(Enemy, List[Spell])], Boolean]
In other words, you provide it with all possible moves, and it simulates all possible states. You can consider it as a kind of decision tree, which branches off every step.
Hence I defined, how to proceed with one spell.
def combineS1(spell: Spell): State[(NonEmptyList[(Enemy, List[Spell])]), Boolean]
// some logic
The problem is, that I can not implement it via simple traverse:
def combineS(variations: NonEmptyList[Spell]): State[NonEmptyList[(Enemy, List[Spell])], Boolean] = {
val x = variations traverse combine1 // State[Nel[..], Nel[Boolean]
x map { _.suml1(conjunction)}
}
Because in traverse, the Nels are not appended to each other, but discarded.
That's why I came up with this solution:
def combineS(variations: NonEmptyList[Spell]): State[NonEmptyList[(Enemy, List[Spell])], AllDead] = {
val x: NonEmptyList[State[NonEmptyList[(Enemy, List[Spell])], Boolean]] = variations map combineS
foldStates(x)(_ && _)(append)
}
That code is actually working, but I feel like there's a way to traverse it, without additional foldState.
What would be other functional approaches to do such simulations (in terms of concepts at least). I can write it simply functional, without using high level concepts, but the purpose of this exercise was exactly to learn advanced stuff.
(May be it is exactly the job for Writer Monad? or Comonad?)
Also, if stackoverflow is not the best place for such questions, please, point out, where such questions are supposed to be asked?
Well, to answer the first part of that, if we were in an alternative universe where Scalaz already had a Biapplicative type class, we could use it as follows:
def foldStatesG[S, A](states: NonEmptyList[State[S, A]], s: (S, S) ⇒ S, a: (A, A) ⇒ A): State[S, A] =
states.foldLeft1(IndexedStateT.indexedStateTBiapplicative[Id, S].bilift2(s, a))
But we don't, so we'd need something like the following (n.b. I haven't ensured this does anything sane law-wise):
trait Biapplicative[F[_, _]] extends Bifunctor[F] {
def bipure[A, B](a: ⇒ A, b: ⇒ B): F[A, B]
def biapply[A, B, C, D](fab: ⇒ F[A, B])(f: ⇒ F[A ⇒ C, B ⇒ D]): F[C, D]
def bilift2[A, B, C, D, E, G](fab: (A, B) ⇒ C, fde: (D, E) ⇒ G): (F[A, D], F[B, E]) ⇒ F[C, G] =
(fad: F[A, D], fbe: F[B, E]) ⇒
biapply(fbe)(bimap[A, D, B ⇒ C, E ⇒ G](fad)(fab.curried, fde.curried))
}
object Biapplicative {
implicit def indexedStateTBiapplicative[F[_], S1](implicit F: Applicative[F]) =
new Biapplicative[IndexedStateT[F, S1, ?, ?]] {
def bipure[A, B](a: ⇒ A, b: ⇒ B) =
StateT.constantIndexedStateT(b)(a)
def biapply[A, B, C, D]
(fab: ⇒ IndexedStateT[F, S1, A, B])
(f: ⇒ IndexedStateT[F, S1, A ⇒ C, B ⇒ D]) =
new IndexedStateT[F, S1, C, D] {
def apply(initial: S1): F[(C, D)] =
F.ap(fab(initial))(F.map(f(initial)) {
case (a2c, b2d) ⇒ Bifunctor[Tuple2].bimap(_)(a2c, b2d)
})
}
}
}
Looking through the haskell free package (http://hackage.haskell.org/package/free-3.4.2) there's a few types that seem simple and useful, that I see almost no literature on outside of haskell, the type I'm interested in now is the Free Applicative.
Now I think that the free applicative builds up chains of function applications as data and maps them (out-of / over) G, (I think...)
where I'm at ...
trait Functor[F[_]] {
def map[A, B](f: A => B): F[A] => F[B]
}
trait Applicative[F[_]] extends Functor[F] {
def ap[A, B](f: F[A => B]): F[A] => F[B]
def apF[A, B](f: F[A])(x: F[A => B]): F[B]
}
trait FreeAp[F[_], A] {
def map[B](f: A => B): FreeAp[F, B] = {
this match {
case Pure(x) => Pure(f(x))
case Ap(x, y) => Ap(x, { y.map(f.compose _) })
}
}
def runAp[G[_]](phi: F ~> G, fa: FreeAp[F, A])(implicit G: Applicative[G]): G[A] = {
fa match {
case Pure(x) => G.pure(x)
case Ap(f, x) => G.apF(phi(f)) { G.map(id[A])(runAp(phi, x)) }
}
}
def runApM[B, M](phi: F ~> ({ type l[x] = M })#l, x: FreeAp[F, B])(implicit M: Monoid[M]): M = {
???
}
}
case class Pure[F[_], A](x: A) extends FreeAp[F, A]
case class Ap[F[_], A, B](x: F[A], y: FreeAp[F, A => B]) extends FreeAp[F, B]
what I'm asking for: the runAp looks so simple in haskell but I've been having some trouble translating... I need a shove in the right direction
runAp :: Applicative g => (forall x. f x -> g x) -> Ap f a -> g a
runAp _ (Pure x) = pure x
runAp u (Ap f x) = flip id <$> u f <*> runAp u x
Ideally I'd like a gentle walk through the free applicative and some help with at least the runAp implementation (but really get into it and spare no detail)
update: so I've been working with this myself and I tried implementing map and I get a variance error, the second case expression gives an error unless FreeAp is contravariant in A, but the first case expression gives an error unless FreeAp isn't contravariant in A...
Any Ideas ?
update: I added the variance annotations from #Cirdec's answer and it didn't suddenly work but I played around and added a annotation [Any, B] to the Ap construction in map and now that definition type checks. so far though no luck with runAp...
update: this is the type error I'm getting on the Ap branch of the runAp pattern match ...
type mismatch; found : core01.FreeAp[F,Any => A] required: core01.FreeAp[F,A]
////
trait Forall[P[_]] {
def apply[A]: P[A]
}
trait ~>[F[_], G[_]] {
def apply[A](x: F[A]): G[A]
}
UPDATE
reading:
http://ro-che.info/articles/2013-03-31-flavours-of-free-applicative-functors.html,
Free Applicative Functors by Paolo Capriotti
//// including the Functor & Applicative definitions above
trait FreeAp[F[_], A] { self =>
def map[B](f: A => B): FreeAp[F, B] = {
this match {
case Pure(x) => Pure(f(x))
case ap: Ap[F, α, _] => Ap(ap.x.map(f.compose(_: α => A)), ap.y)
}
}
}
case class Pure[F[_], A](x: A) extends FreeAp[F, A]
case class Ap[F[_], A, B](x: FreeAp[F, A => B], y: F[A]) extends FreeAp[F, B]
def liftAp[F[_], A](x: F[A]): FreeAp[F, A] = Ap[F, A, A](Pure(id), x)
def runAp[F[_], G[_], A](implicit G: Applicative[G]): (F ~> G) => FreeAp[F, A] => G[A] = {
(u: F ~> G) =>
(fa: FreeAp[F, A]) => fa match {
case Pure(x) => G.pure(x)
case ap: Ap[F, α, _] => {
val gf: G[(α => A) => A] = G.map(curry(flip(id[α => A])))(u(ap.y))
val gx: G[α => A] = runAp(G)(u)(ap.x)
G.ap(gf)(gx)
}
}
}
trait FreeApFunctor[F[_]] extends Functor[({ type l[x] = FreeAp[F, x] })#l] {
final override def map[A, B](f: A => B): FreeAp[F, A] => FreeAp[F, B] = _ map f
}
trait FreeApSemiapplicative[F[_]] extends Apply[({ type l[x] = FreeAp[F, x] })#l] with FreeApFunctor[F] {
final def ap[A, B](f: => FreeAp[F, A => B]): FreeAp[F, A] => FreeAp[F, B] = {
(fa: FreeAp[F, A]) => f match {
case Pure(x) => map(x)(fa)
case a: Ap[F, α, _] => Ap(ap{ map(flip[α, A, B])(a.x) }(fa), a.y)
}// ^^^
// type mismatch; found : core01.FreeAp[F,α => _] required: core01.FreeAp[F,(α, A) => B]
}
}
Traits
First, you'll need to get what Applicative and Functor are correct. Let's start with Functor. I'm going to use the Haskell names and argument orders for everything, where I can:
class Functor f where
fmap :: (a -> b) -> f a -> f b
trait Functor[F[+_]] {
def fmap[A,B]: (A => B) => F[A] => F[B]
}
Now Applicative. Your Applicative is missing that an Applicative first must be a Functor and that an Applicative has a way to make one from a value. The type for apF also seems to be incorrect; it should allow you to apply a function that is stuck inside the functor to a value that is also stuck inside the functor.
class Functor f => Applicative f where
pure :: a-> f a
(<*>) :: f (a -> b)-> f a -> f b
trait Applicative[F[+_]] extends Functor[F] {
def pure[A]: A => F[A]
def apF[A,B]: F[A => B] => F[A] => F[B]
}
I'd suggest you make something else that's applicative before jumping all the way to free applicative, perhaps the Identity functor and its applicative instance. Hopefully this will help you understand what you need to be making for the free applicative instance.
Data Types and Variance
Now we need the data types.
data Ap f a where
Pure :: a -> Ap f a
Ap :: f a -> Ap f (a -> b) -> Ap f b
In Scala, these are represented by case classes:
sealed abstract class FreeAp[F[+_],+A]
case class Pure[F[+_], +A](a: A) extends FreeAp[F, A]
case class Ap[F[+_], A, +B](x: F[A], fg: FreeAp[F,A=>B]) extends FreeAp[F, B]
In order for Scala's variant types to work, we annotated these with variance, and marked the variance correctly on our traits as well. This is normal in languages with variant type systems, a similar interface in c# would require in and out annotation to be generally useful and match the expectations of programmers using libraries. If you really hate variance, you can remove all the variance annotations from my answer, and it still works - you just won't have variant interfaces.
Instances
We can start porting the instances for Functor and Applicative:
instance Functor (Ap f) where
fmap f (Pure a) = Pure (f a)
fmap f (Ap x y) = Ap x ((f .) <$> y)
instance Applicative (Ap f) where
pure = Pure
Pure f <*> y = fmap f y
Ap x y <*> z = Ap x (flip <$> y <*> z)
Functor and Applicative Instances
A functor instance in Scala is difficult to write, due to the fact that there aren't really universally quantified types. With universally quantified types, flip and compose could both be used below without explicit types. We can get around this by binding a type variable, a, in pattern matching, which is done by the pattern ap: Ap[F,a,_]. The type variable is used to provide the explicit types .compose(_ : a => A) and flip[a,A,B].
class FreeApInstances[F[+_]] {
implicit object FreeApApplicativeInstance extends Applicative[({type f[+x] = FreeAp[F, x]})#f] {
// Functor
final def fmap[A,B]: (A=>B) => FreeAp[F,A] => FreeAp[F,B] =
(f: A=>B) => (fa: FreeAp[F,A]) => fa match {
case Pure(a) => Pure(f(a))
case ap: Ap[F, a, _] => Ap(ap.x, fmap(f.compose(_ : a => A))(ap.fg))
}
// Applicative
final def pure[A]: A => FreeAp[F,A] =
(a: A) => Pure(a)
final def apF[A, B]: FreeAp[F,A=>B] => FreeAp[F,A] => FreeAp[F,B] =
(ff: FreeAp[F,A=>B]) => (fa: FreeAp[F,A]) => ff match {
case Pure(f) => fmap(f)(fa)
case ap: Ap[F, a, _] => Ap(ap.x, apF(fmap(flip[a,A,B])(ap.fg))(fa))
}
}
}
flip, which is needed for Applicative, just flips the order of two arguments:
def flip[A,B,C]: (A => B => C) => B => A => C =
(f: (A => B => C)) => (b: B) => (a: A) => f(a)(b)
runAp
Finally, we can port runAp:
-- | Given a natural transformation from #f# to #g#, this gives a canonical monoidal natural transformation from #'Ap' f# to #g#.
runAp :: Applicative g => (forall x. f x -> g x) -> Ap f a -> g a
runAp _ (Pure x) = pure x
runAp u (Ap f x) = flip id <$> u f <*> runAp u x
This requires a universal quantification for forall x. f x -> g x. We can satisfy this one with the usual trick for languages with generics - add a generic member to something; the member can then provide something for all types, though we will need to be able to explicitly provide the type. You have clearly already found a Scala type for natural transformations:
trait ~>[F[_],G[_]] { def apply[B](f: F[B]): G[B] }
Again, we'll bind a type variable a from the pattern ap: Ap[F, a _] to get the type that Scala can't infer, id: (a=>A) => a => A.
def runAp[F[_],G[_],A](implicit g: Applicative[G]):
(F ~> G) => FreeAp[F,A] => G[A] =
(u: F ~> G) => (fa: FreeAp[F,A]) => fa match {
case Pure(x) => g.pure(x)
case ap: Ap[F, a, _] => {
val gf: G[(a=>A)=>A] = g.fmap(flip(id[a=>A]))(u.apply(ap.x))
val gx: G[a=>A] = runAp(g)(u)(ap.fg)
g.apF(gf)(gx)
}
}
id is just the identity function:
def id[A]: A => A =
(x:A) => x
In Haskell, liftM2 can be defined as:
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f m1 m2 = do
x1 <- m1
x2 <- m2
return $ f x1 x2
I'd like to translate this to Scala. My first attempt was the following:
def liftM2[T1, T2, R, M[_]](f: (T1, T2) => R)(ma: M[T1], mb: M[T2]) : M[R] = for {
a <- ma
b <- mb
} yield f(a, b)
This fails in what I guess is the most obvious way possible: "value flatMap is not a member of type parameter M[T1]". Right, I haven't indicated that M[_] is some kind of monad. So the next thing I tried was to define some structural type like:
type Monad[A] = {
def flatMap[B](f: (A) => Monad[B]): Monad[B]
}
... and to have M[A] <: Monad[A]. But that doesn't work, because Scala doesn't have recursive structural types.
So the next few things I tried involved gyrations similar to M[A] <: FilterMonadic[A, _]. Those all failed, probably because I wasn't able to figure out the right implicit-fu for CanBuildFrom.
The most closely-related question I could find here on StackOverflow was this one, touching both on recursive structural types and how to mimic Haskell's typeclasses in Scala. But that approach requires defining an implicit conversion from each type you care about to the trait defining the typeclass, which seems terribly circular in this case...
Is there any good way to do what I'm trying to do?
The usual way to encode type classes in Scala turns out to follow Haskell pretty closely: List doesn't implement a Monad interface (as you might expect in an object-oriented language), but rather we define the type class instance in a separate object.
trait Monad[M[_]] {
def point[A](a: => A): M[A]
def bind[A, B](ma: M[A])(f: A => M[B]): M[B]
def map[A, B](ma: M[A])(f: A => B): M[B] = bind(ma)(a => point(f(a)))
}
implicit object listMonad extends Monad[List] {
def point[A](a: => A) = List(a)
def bind[A, B](ma: List[A])(f: A => List[B]) = ma flatMap f
}
This idea is introduced in Poor Man's Type Classes and explored more deeply in Type Classes as Objects and Implicits. Notice that the point method could not have been defined in an object-oriented interface, as it doesn't have M[A] as one of it's arguments to be converted to the this reference in an OO encoding. (Or put another way: it can't be part of an interface for the same reason a constructor signature can't be represented in an interface.)
You can then write liftM2 as:
def liftM2[M[_], A, B, C](f: (A, B) => C)
(implicit M: Monad[M]): (M[A], M[B]) => M[C] =
(ma, mb) => M.bind(ma)(a => M.map(mb)(b => f(a, b)))
val f = liftM2[List, Int, Int, Int](_ + _)
f(List(1, 2, 3), List(4, 5)) // List(5, 6, 6, 7, 7, 8)
This pattern has been applied extensively in Scalaz. Version 7, currently in development, includes an index of the type classes.
In addition to providing type classes and instances for standard library types, it provides a 'syntactic' layer that allows the more familiar receiver.method(args) style of method invocation. This often affords better type inference (accounting for Scala's left-to-right inference algorithm), and allows use of the for-comprehension syntactic sugar. Below, we use that to rewrite liftM2, based on the map and flatMap methods in MonadV.
// Before Scala 2.10
trait MonadV[M[_], A] {
def self: M[A]
implicit def M: Monad[M]
def flatMap[B](f: A => M[B]): M[B] = M.bind(self)(f)
def map[B](f: A => B): M[B] = M.map(self)(f)
}
implicit def ToMonadV[M[_], A](ma: M[A])
(implicit M0: Monad[M]) =
new MonadV[M, A] {
val M = M0
val self = ma
}
// Or, as of Scala 2.10
implicit class MonadOps[M[_], A](self: M[A])(implicit M: Monad[M]) {
def flatMap[B](f: A => M[B]): M[B] = M.flatMap(self)(f)
def map[B](f: A => B): M[B] = M.map(self)(f)
}
def liftM2[M[_]: Monad, A, B, C](f: (A, B) => C): (M[A], M[B]) => M[C] =
(ma, mb) => for {a <- ma; b <- mb} yield f(a, b)
Update
Yep, its possible to write less generic version of liftM2 for the Scala collections. You just have to feed in all the required CanBuildFrom instances.
scala> def liftM2[CC[X] <: TraversableLike[X, CC[X]], A, B, C]
| (f: (A, B) => C)
| (implicit ba: CanBuildFrom[CC[A], C, CC[C]], bb: CanBuildFrom[CC[B], C, CC[C]])
| : (CC[A], CC[B]) => CC[C] =
| (ca, cb) => ca.flatMap(a => cb.map(b => f(a, b)))
liftM2: [CC[X] <: scala.collection.TraversableLike[X,CC[X]], A, B, C](f: (A, B) => C)(implicit ba: scala.collection.generic.CanBuildFrom[CC[A],C,CC[C]], implicit bb: scala.collection.generic.CanBuildFrom[CC[B],C,CC[C]])(CC[A], CC[B]) => CC[C]
scala> liftM2[List, Int, Int, Int](_ + _)
res0: (List[Int], List[Int]) => List[Int] = <function2>
scala> res0(List(1, 2, 3), List(4, 5))
res1: List[Int] = List(5, 6, 6, 7, 7, 8)