Reputation: 572
I am still learning Scala - So please forgive me if this is extremely simple to accomplish. I am also not very fluent with Scalaz or Shapeless - I am only beginning to explore those libraries. I am looking for a simple treatise somewhere which explains to me how I can do something like
trait AmazingMalini[F[G[_]]] {
def fMap[A,B](aa: F[G[A]])(f : A => F[G[B]]) : F[G[B]]
}
And then I wanna be able to do something like this -
trait SomeCrazyMagicWithList extends AmazingMalini[Option[List]]{
def fMap[A,B](aa: Option[List[A]])(f : A => Option[List[B]]) :Option[List[B]] = ???
}
Note that option or list types are just examples I have a few container types that I would replace there in mind (building a small graph traversal like DSL for for an app).
Upvotes: 3
Views: 235
Reputation: 68640
You have to change the signature of AmazingMalini
to trait AmazingMalini[F[_], G[_]]
The method could then be implemented like this:
trait AmazingMalini[F[_], G[_]] {
def fMap[A,B](aa: F[G[A]])(f : A => F[G[B]]) : F[G[B]]
}
trait SomeCrazyMagicWithList extends AmazingMalini[Option, List] {
def fMap[A, B](aa: Option[List[A]])(f: A => Option[List[B]]): Option[List[B]] =
aa.flatMap {
_ match {
case Nil => Some(Nil)
case as: List[A] => as.map(f).reduce(concat(_, _))
}
}
def concat[A](x: Option[List[A]], y: Option[List[A]]): Option[List[A]] = for {
xs <- x
ys <- y
} yield xs ++ ys
}
Note that Scalaz provides monad transformers to enable stacking of certain monads. For example:
OptionT
transformer enables stacking of any monad on top of Option
: List[Option[A]]
, Future[Option[A]]
, etc.ListT
transformer enables stacking of any monad on top of List
: Option[List[A]]
, Future[List[A]]
.So, in your case, you could use ListT
like this:
import scalaz._
import Scalaz._
import ListT._
listT(List(1,2,3).some).flatMap(i => listT(List(i, i * 3).some))
res0: scalaz.ListT[Option,Int] = ListT(Some(List(1, 3, 2, 6, 3, 9)))
You can also use for-comprehensions with monad transformers:
for {
x <- listT(List(1,2).some)
y <- listT(List(3,4).some)
} yield x + y
res2: scalaz.ListT[Option,Int] = ListT(Some(List(4, 5, 5, 6)))
Upvotes: 5