I'm trying to implement map and flatMap as an extension/enrichment for Option, without cheating and looking at how it was implemented in Scalaz.
So here's what I got so far before I got stuck:
package extensions.monad
trait Monad[M[_]] {
// >>= :: Monad m => m a -> (a -> m b) -> m b
def flatMap[A, B](input: A => M[B]): M[B]
}
trait Functor[F[_]] {
// fmap :: Functor f => (a -> b) -> f a -> f b
def map[A, B](input: A => B): F[B]
}
object MOption {
implicit class MonadicOption[A](left: Option[A]) extends Monad[Option[A]] with Functor[Option[A]] {
def flatMap[A, B](right: A => Option[B]): Option[B] = ???
def map[A, B](right: A => B): Option[B] = ???
}
}
All I really need is the basic functionality, so I can do something like this:
Some(3).flatMap(x => Some(4).map(y => x + y))
Any hints?
def flatMap[A, B](right: A => Option[B]): Option[B] = left match {
None => None
Some(x) => right(x)
}
or similarly to what the scala std library does
def flatMap[A, B](right: A => Option[B]): Option[B] =
if (left.isEmtpy) None else right(left.get)
Related
I was trying to apply typeclass pattern in scala and tried implementing Functor, Applicative and Monad typeclasses as follows
trait Functor[F[_]] {
def fmap[A, B] : (A => B) => F[A] => F[B]
}
object Functor {
def fmap[A, B, F[_]] (implicit ev: Functor[F]) = ev.fmap
}
trait Applicative[F[_]] {
def pure[A]: A => F[A]
def apply[A, B]: F[A => B] => F[A] => F[B]
}
object Applicative {
def pure[A, F[_]: Applicative]: A => F[A] = implicitly[Applicative[F]].pure
def apply[A, B, F[_]: Applicative]: F[A => B] => F[A] => F[B] = implicitly[Applicative[F]].apply
def liftA2[A, B, C, F[_]: Functor: Applicative]: (A => B => C) => F[A] => F[B] => F[C] =
f => fa => fb => implicitly[Applicative[F]].apply(implicitly[Functor[F]].fmap(f)(fa))(fb)
}
trait Monad[M[_]] {
def bind[A, B]: M[A] => (A => M[B]) => M[B]
def ret[A]: A => M[A]
}
object Monad {
def bind[A, B, M[_] :Monad]: M[A] => (A => M[B]) => M[B] = implicitly[Monad[M]].bind
def ret[A, M[_] :Monad]: A => M[A] = implicitly[Monad[M]].ret
}
sealed trait Maybe[A]
case class Some[A](value: A) extends Maybe[A]
case object None extends Maybe[Void] {
def apply[A]: Maybe[A] = None.asInstanceOf[Maybe[A]]
}
object Maybe {
def apply[A] (value: A): Maybe[A] = Some(value)
implicit object MaybeOps extends Functor[Maybe] with Applicative[Maybe] with Monad[Maybe] {
override def fmap[A, B]: (A => B) => Maybe[A] => Maybe[B] =
fn => ma => ma match {
case Some(a) => Maybe(fn(a))
case _ => None.apply
}
override def pure[A]: A => Maybe[A] = Some(_)
override def ret[A]: A => Maybe[A] = Some(_)
override def apply[A, B]: Maybe[A => B] => Maybe[A] => Maybe[B] = mab => ma => mab match {
case Some(f) => fmap(f)(ma)
case _ => None.apply
}
override def bind[A, B]: Maybe[A] => (A => Maybe[B]) => Maybe[B] = ma => f => ma match {
case Some(a) => f(a)
case _ => None.apply
}
}
}
And the consumer logic where I get to apply bind, fmap functions on Maybe datatype does not typecheck:
val a: Maybe[Int] = Maybe(10)
val p: Maybe[String] = bind.apply(Maybe(10))((i: Int) => Maybe(s"$i values"))
val q = fmap.apply(i => s"$i !!")(p)
println(p)
println(q)
The above code getting the error as
Error: (15, 29) type mismatch; found: String required: Nothing val q = fmap.apply(i => s"$i !!")(p)
I didn't want to extend the trait to make it work. Since the context-bounds specify the requirement of Monad typeclass to require an instance of Applicative in scope. Is there any clean way to support this in scala?
Editing the above code as per #Mateusz Kubuszok comments, worked fine for me.
trait Functor[F[_]] {
//def fmap[A, B] : (A => B) => F[A] => F[B]
def fmap[A, B](f: A => B, fa: F[A]): F[B]
}
object Functor {
//def fmap[A, B, F[_]] (implicit ev: Functor[F]) = ev.fmap
def fmap[A, B, F[_]](f: A => B, fa: F[A]) (implicit ev: Functor[F]) = ev.fmap(f, fa)
}
trait Applicative[F[_]] {
//def pure[A]: A => F[A]
def pure[A](a: A) : F[A]
//def apply[A, B]: F[A => B] => F[A] => F[B]
def appl[A, B](f: F[A=>B], fa: F[A]): F[B]
}
object Applicative {
//def pure[A, F[_]: Applicative]: A => F[A] = implicitly[Applicative[F]].pure
def pure[A, F[_]](a: A)(implicit ev: Applicative[F]) = ev.pure(a)
//def apply[A, B, F[_]: Applicative]: F[A => B] => F[A] => F[B] = implicitly[Applicative[F]].apply
def appl[A, B, F[_]] (f: F[A => B], fa: F[A])(implicit ev: Applicative[F]): F[B]=
ev.appl(f, fa)
def liftA2[A, B, C, F[_]: Functor: Applicative] (f: (A => B => C), fa: F[A], fb: F[B]): F[C] =
implicitly[Applicative[F]].appl(implicitly[Functor[F]].fmap(f, fa), fb)
}
trait Monad[M[_]] {
//def bind[A, B]: M[A] => (A => M[B]) => M[B]
def bind[A, B](ma: M[A], f: A => M[B]): M[B]
//def ret[A]: A => M[A]
def ret[A](a: A): M[A]
}
object Monad {
// def bind[A, B, M[_] :Monad]: M[A] => (A => M[B]) => M[B] = implicitly[Monad[M]].bind
def bind[A, B, M[_] :Monad](ma: M[A], f: (A => M[B])): M[B] = implicitly[Monad[M]].bind(ma, f)
//def ret[A, M[_] :Monad]: A => M[A] = implicitly[Monad[M]].ret
def ret[A, M[_] :Monad](a: A)(implicit ev: Monad[M]): M[A] = ev.ret(a)
}
sealed trait Maybe[A]
case class Some[A](value: A) extends Maybe[A]
case object None extends Maybe[Void] {
def apply[A]: Maybe[A] = None.asInstanceOf[Maybe[A]]
}
object Maybe {
def apply[A] (value: A): Maybe[A] = Some(value)
implicit object MaybeOps extends Functor[Maybe] with Applicative[Maybe] with Monad[Maybe] {
override def fmap[A, B](f: (A => B), ma: Maybe[A]): Maybe[B] =
ma match {
case Some(a) => Maybe(f(a))
case _ => None.apply
}
override def pure[A](a: A) : Maybe[A] = Some(a)
override def ret[A](a: A) : Maybe[A] = Some(a)
override def appl[A, B] (mab: Maybe[A => B], ma: Maybe[A]): Maybe[B] = mab match {
case Some(f) => fmap(f, ma)
case _ => None.apply
}
override def bind[A, B](ma: Maybe[A], f: (A => Maybe[B])) : Maybe[B] = ma match {
case Some(a) => f(a)
case _ => None.apply
}
}
}
import io.github.senthilganeshs.typeclass.Monad.bind
import io.github.senthilganeshs.typeclass.Functor.fmap
import io.github.senthilganeshs.types.Maybe
object Main {
def main(args: Array[String]): Unit = {
import io.github.senthilganeshs.types.Maybe._
val a: Maybe[Int] = Maybe(10)
val p: Maybe[String] = bind(Maybe(10), (i: Int) => Maybe(s"$i values"))
val q: Maybe[String] = fmap((i: String) => s"$i !!", p)
println(p)
println(q)
}
}
How do I remove explicit casting asInstanceOf[XList[B]] in Cons(f(a), b).asInstanceOf[XList[B]] inside map function? Or perhaps redesign reduce and map functions altogether? Thanks
trait XList[+A]
case object Empty extends XList[Nothing]
case class Cons[A](x: A, xs: XList[A]) extends XList[A]
object XList {
def apply[A](as: A*):XList[A] = if (as.isEmpty) Empty else Cons(as.head, apply(as.tail: _*))
def empty[A]: XList[A] = Empty
}
def reduce[A, B](f: B => A => B)(b: B)(xs: XList[A]): B = xs match {
case Empty => b
case Cons(y, ys) => reduce(f)(f(b)(y))(ys)
}
def map[A, B](f: A => B)(xs: XList[A]): XList[B] = reduce((b: XList[B]) => (a: A) => Cons(f(a), b).asInstanceOf[XList[B]])(XList.empty[B])(xs)
You can merge two argument lists into one by replacing )( by ,:
def reduce[A, B](f: B => A => B, b: B)(xs: XList[A]): B = xs match {
case Empty => b
case Cons(y, ys) => reduce(f, f(b)(y))(ys)
}
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce((b: XList[B]) => (a: A) => Cons(f(a), b), XList.empty[B])(xs)
This will force the type inference algorithm to consider both first arguments of reduce before making up its mind about what B is supposed to be.
You can either widen Cons to a XList[B] at the call site by providing the type parameters explicitly:
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce[A, XList[B]]((b: XList[B]) => (a: A) => Cons(f(a), b))(XList.empty[B])(xs)
Or use type ascription:
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce((b: XList[B]) => (a: A) => Cons(f(a), b): XList[B])(XList.empty[B])(xs)
As a side note, reduce is traditionally more strict at the method definition than what you've written. reduce usually looks like this:
def reduce[A](a0: A, a: A): A
Implicitly requiring a non empty collection to begin with. What you've implemented is similar in structure to a foldLeft, which has this structure (from Scalas collection library):
def foldLeft[B](z: B)(op: (B, A) => B): B
Does there exist a utility in Scala or Scalaz to transform a container/collection of functions to a function that maps from the same input to a collection output values? The signature would look something like
def transform[M[_], A, B](m: M[A => B]): A => M[B] = ???
Here's an example implementation for the List container:
def transform[A, B](fs: List[A => B]): A => List[B] = x =>
fs.foldRight[List[B]](Nil) {
(f, acc) => f(x) :: acc
}
Ideally, this would work for any function container, including a tuple of functions, an Option[Function1[A, B]], or even a TupleN[Option[Function1[A, B]], ...].
EDIT:
I've just realized that (at least for the special case of a List) the map function works:
def transform[A, B](fs: List[A => B]): A => List[B] = x => fs map (_(x))
This can generalize to anything that has a map function with the appropriate semantics. What's the appropriate type class for this?
Assuming M is a Functor, mapply in scalaz's Functor has a similar type signature:
def mapply[A, B](a: A)(f: F[A => B]): F[B] = map(f)((ff: A => B) => ff(a))
So you could write transform in terms of that:
def transform[M[_],A,B](m: M[A => B])(implicit f:Functor[M]):A => M[B] = f.mapply(_)(m)
Edit: Another implementation using features from FunctorSyntax:
def transform[M[_]:Functor,A,B](m: M[A => B]):A => M[B] = _.mapply(m)
I searched through the Scalaz source code and it looks like Functor does the trick:
def transform[M[_]: Functor, A, B](fs: M[A => B]): A => M[B] = a => fs map (_(a))
Continuing on Functional Programming in Scala's exercises, I'm trying to implement:
def sequence[A](n: Int, ma: F[A]): F[List[A]]
Except for traverse, replicateOnce and replicateM, which I wrote, author is #pchiusano EDIT (spelled name incorrectly, sorry)
trait Monad[F[_]] extends Functor[F] {
def unit[A](a: => A): F[A]
def flatMap[A,B](ma: F[A])(f: A => F[B]): F[B]
def map[A,B](ma: F[A])(f: A => B): F[B] =
flatMap(ma)(a => unit(f(a)))
def map2[A, B, C](ma: F[A], mb: F[B])(f: (A,B) => C): F[C] =
flatMap(ma)(a => map(mb)(b => f(a, b)))
// Exercise 3: implement sequence() and traverse
// official answer from #pchiusano
def sequence[A](lma: List[F[A]]): F[List[A]] =
lma.foldRight(unit(List[A]()))((ma, mla) => map2(ma, mla)(_ :: _))
def traverse[A, B](la: List[A])(f: A => F[B]): F[List[B]] =
la.foldRight(unit(List[B]()))((ma, mla) => map2(f(ma), mla)(_ :: _))
def replicateOnce[A](ma: F[A]): F[List[A]] = {
map(ma)(x => List(x))
}
For replicateM, I'm getting a compile-time error, error: overloaded method value fill with alternatives.
// Exercise 4: implement replicateM
def replicateM[A](n: Int, ma: F[A]): F[List[A]] = {
sequence(List.fill(n, ma))
}
}
Please point me in the right direction as I'm a bit stuck.
You're calling List.fill incorrectly, it's a partially applied function so you need to first apply n and then ma:
def replicateM[A](n: Int, ma: F[A]): F[List[A]] = {
sequence(List.fill(n)(ma)) //note that the comma is removed
}
What is the best way to partition Seq[A \/ B] into (Seq[A], Seq[B]) using Scalaz?
There is a method: separate defined in MonadPlus. This typeclass is a combination a Monad with PlusEmpty (generalized Monoid). So you need to define instance for Seq:
1) MonadPlus[Seq]
implicit val seqmp = new MonadPlus[Seq] {
def plus[A](a: Seq[A], b: => Seq[A]): Seq[A] = a ++ b
def empty[A]: Seq[A] = Seq.empty[A]
def point[A](a: => A): Seq[A] = Seq(a)
def bind[A, B](fa: Seq[A])(f: (A) => Seq[B]): Seq[B] = fa.flatMap(f)
}
Seq is already monadic, so point and bind are easy, empty and plus are monoid operations and Seq is a free monoid
2) Bifoldable[\/]
implicit val bife = new Bifoldable[\/] {
def bifoldMap[A, B, M](fa: \/[A, B])(f: (A) => M)(g: (B) => M)(implicit F: Monoid[M]): M = fa match {
case \/-(r) => g(r)
case -\/(l) => f(l)
}
def bifoldRight[A, B, C](fa: \/[A, B], z: => C)(f: (A, => C) => C)(g: (B, => C) => C): C = fa match {
case \/-(r) => g(r, z)
case -\/(l) => f(l, z)
}
}
Also easy, standard folding, but for type constructors with two parameters.
Now you can use separate:
val seq: Seq[String \/ Int] = List(\/-(10), -\/("wrong"), \/-(22), \/-(1), -\/("exception"))
scala> seq.separate
res2: (Seq[String], Seq[Int]) = (List(wrong, number exception),List(10, 22, 1))
Update
Thanks to Kenji Yoshida, there is a Bitraverse[\/], so you need only MonadPlus.
And a simple solution using foldLeft:
seq.foldLeft((Seq.empty[String], Seq.empty[Int])){ case ((as, ai), either) =>
either match {
case \/-(r) => (as, ai :+ r)
case -\/(l) => (as :+ l, ai)
}
}