Typeclass and the scala Collection Interface - scala

I am trying to implement a function that would work on types that have a map and a flatMap method. I have already made it for Traversable, but this does not include Future and Option directly. So I have decided to go with my own interface, using a typeclass:
trait CanMap[A, M[_]] {
def map[B](l: M[A])(f: A => B): M[B]
def flatMap[B](l: M[A])(f: A => M[B]): M[B]
}
I already implemented this for Option:
implicit def canmapopt[A] = new CanMap[A, Option] {
def map[B](l: Option[A])(f: A => B): Option[B] = l.map(f)
def flatMap[B](l: Option[A])(f: A => Option[B]): Option[B] = l.flatMap(f)
}
and this one works very well. Now I wanted to implement it for any subtype of Traversable, I tried an implementation very close to the one for Option:
implicit def canmaptrav[A, B, T[B] <: Traversable[B]] = new CanMap[A, T] {
def map[B](l: T[A])(f: A => B): T[B] = l.map(f)
def flatMap[B](l: T[A])(f: A => T[B]): T[B] = l.flatMap(f)
}
but I get the error:
type mismatch; found : Traversable[B] required: T[B] Note: implicit method canmaptrav is not applicable here because it comes after the application point and it lacks an explicit result type
for the return type of l.map. I cannot understand why l.map(f) would return a Traversable and not the specific type T[B]. So I tried to explicitelly put the right type of CanBuildFrom in the context:
implicit def canmaptrav[A, B, T[B] <: Traversable[B]](implicit cbf: CanBuildFrom[T[A], B, T[B]]) = new CanMap[A, T] {
def map[B](l: T[A])(f: A => B): T[B] = l.map(f)
def flatMap[B](l: T[A])(f: A => T[B]): T[B] = l.flatMap(f)
}
The error persists.
Any idea where I went wrong? It might be obvious but I am getting confused with the generic type signatures I guess.
Update: Solution
First of all, as the answers pointed out, CanMap is mostly a Functor/Monad, so if you dare, you can use scalaz to implement this. However, if you are like me and want to try without it, here is the solution, based on the answer by Kipton Barros:
trait CanMap[A, B, M[_]] {
def map(l: M[A])(f: A => B): M[B]
def flatMap(l: M[A])(f: A => M[B]): M[B]
}
implicit def canmapopt[A, B] = new CanMap[A, B, Option] {
def map(l: Option[A])(f: A => B): Option[B] = l.map(f)
def flatMap(l: Option[A])(f: A => Option[B]): Option[B] = l.flatMap(f)
}
implicit def canmaptrav[A, B, M[+_]](implicit bf: CanBuildFrom[M[A], B, M[B]], ev: M[A] => TraversableLike[A, M[A]], eb: M[B] => TraversableLike[B, M[B]]) = new CanMap[A, B, M] {
def map(l: M[A])(f: (A) => B): M[B] = l.map(f)
def flatMap(l: M[A])(f: A => M[B]): M[B] = l.flatMap[B, M[B]] { (a: A) =>
f(a)
}
}
The trick is to use an implicit conversion M[A] => TraversableLike[A, M[A]] instead of trying to subtype Traversable.

The first problem is that there's a lot going on "under the hood" in the Traversable map method. It does a bit of work to return the most specific collection type, which is why you need CanBuildFrom. The second problem is that Option does not implement the Traversable interface, so its map method doesn't take a CanBuildFrom.
Here's the closest I could get,
import scala.collection.generic.CanBuildFrom
import collection.TraversableLike
trait CanMap[A, M[_]] {
def map[B](l: M[A])(f: A => B)(implicit bf: CanBuildFrom[M[A], B, M[B]]): M[B]
}
object Test {
// ugly hack to work around nonexistent CanBuildFrom for Option
implicit def optionBuilder[A, B]: CanBuildFrom[Option[A], B, Option[B]] = null
implicit def canmapopt[A] = new CanMap[A, Option] {
def map[B](l: Option[A])(f: A => B)(implicit bf: CanBuildFrom[Option[A], B, Option[B]]): Option[B] = l.map(f)
}
implicit def canmaptrav[A, M[_]](implicit ev: M[A] => TraversableLike[A, M[A]]) = new CanMap[A, M] {
def map[B](l: M[A])(f: (A) => B)(implicit bf: CanBuildFrom[M[A], B, M[B]]): M[B] = l.map(f)
}
// example usage
def mapper[A, B, M[_]](l: M[A])(f: A => B)(implicit cm: CanMap[A,M], bf: CanBuildFrom[M[A], B, M[B]]) = {
cm.map(l)(f)
}
mapper(List(1,2,3))(_ + 1) // List(2,3,4)
mapper(Some(2): Option[Int])(_ + 1) // Some(3)
// (cast to Option[Int] is needed to find the canmapopt implicit)
}
By the way, the implicit conversion to TraversableLike makes this also work with arrays,
mapper(Array(1,2,3))(_ + 1) // Array(2, 3, 4)

Firstly I tried your two failed attempts and didn't got much out of it. Then I decided to go simple and do my own CanMap implementation. I ended up with this:
def canmaptrav[A] = new CanMap[A, Traversable]{
def map[B](l: Traversable[A])(f: A => B): Traversable[B]= l.map(f)
def flatMap[B](l: Traversable[A])(f: A => Traversable[B]): Traversable[B] = l.flatMap(f)
}
Looking exactly the CanMap[_,Option]. Assuming the subtypes you are looking for is for use cases like this:
canmaptrav[Int].map(List(1,2,3,4))(_ + 1) //> res0: Traversable[Int] = List(2, 3, 4, 5)
canmaptrav[Int].map(Vector(1,2,3,4))(_ + 1) //> res1: Traversable[Int] = Vector(2, 3, 4, 5)
Now, if you want res1 and res0 types to be the concrete types (List, Vector) than the approach will have to indeed rely on the CanBuildFrom from.
BTW, you know that the CanMap is almost the Monad interface, right?

Scalaz already includes these typeclasses and they are called Monad and Functor. A short example:
// map
def foo[F[_] : Functor](xs: F[Int]) = xs.map(_ + 1)
scala> foo(List(1,2,3))
res2: List[Int] = List(2, 3, 4)
// flatMap
def flatten[M[_] : Monad](xs: M[M[Int]]) = xs.flatMap(identity)
scala> flatten(List(List(1,2,3)))
res3: List[Int] = List(1, 2, 3)
edit:
The functor instance for Future could look like this:
implicit object FutureFunctor extends Functor[Future] {
def map[A,B](fa: Future[A])(f: A => B) = fa.map(f)
}

Related

How to transform a collection of tuples with scala 2.13

I'd like to migrate the following code from Scala 2.12 to 2.13
Given any collection of tuples Coll[(A, B)] and a method f: B => IterableOnce[C], I'd like to produce a Coll[(A, C)] by applying f on the second element of the tuple.
implicit class TuplesOps[A, B, Repr <: Traversable[(A, B)]](val s: TraversableLike[(A, B), Repr]) extends AnyVal {
def flatMapValues[C, That](f: B => TraversableOnce[C])(implicit bf: CanBuildFrom[Repr, (A, C), That]) =
s.flatMap { case (a, b) => f(b).map((a, _))}
}
I know that the collection API has changed in 2.13 and I read : https://docs.scala-lang.org/overviews/core/custom-collection-operations.html
I've tried 2 implementations
First
import scala.collection.{ AbstractView, BuildFrom }
import scala.collection.generic.IsSeq
object Evidence extends App {
class TuplesOps[Repr, S <: IsSeq[Repr]](coll: Repr, seq: S) {
def flatMapValues[B, C, D, That](f: C => IterableOnce[D])(implicit bf: BuildFrom[Repr, (B, D), That], ev: seq.A =:= (B, C)): That = {
val seqOps = seq(coll)
bf.fromSpecific(coll)(new AbstractView[(B, D)] {
override def iterator: Iterator[(B, D)] = {
seqOps.flatMap { x => f(ev(x)._2).map((ev(x)._1, _))}.iterator
}
})
}
}
implicit def TuplesOps[Repr](coll: Repr)(implicit seq: IsSeq[Repr]): TuplesOps[Repr, seq.type] =
new TuplesOps(coll, seq)
List("a"->1, "b"->2).flatMapValues{(x:Int) => Seq.fill(x)("x")}
}
And I have this compilation error :
[error] /home/yamo/projects/perso/coll213/src/main/scala/example/Evidence.scala:22:37: diverging implicit expansion for type scala.collection.BuildFrom[List[(String, Int)],(B, String),That]
[error] starting with method Tuple9 in object Ordering
[error] List("a"->1, "b"->2).flatMapValues{(x:Int) => Seq.fill(x)("x")}
Second
import scala.collection.{ AbstractView, BuildFrom }
import scala.collection.generic.IsSeq
object Aux extends App {
type Aux[Repr, B, C] = IsSeq[Repr] { type A = (B, C)}
class TuplesOps[Repr, B, C, S <: Aux[Repr, B, C]](coll: Repr, seq: S) {
def flatMapValues[D, That](f: C => IterableOnce[D])(implicit bf: BuildFrom[Repr, (B, D), That]): That = {
val seqOps = seq(coll)
bf.fromSpecific(coll)(new AbstractView[(B, D)] {
// same as before
override def iterator: Iterator[(B, D)] = {
seqOps.flatMap { case (b, c) => f(c).map((b, _))}.iterator
}
})
}
}
implicit def TuplesOps[Repr, B, C](coll: Repr)(implicit seq: Aux[Repr, B, C]): TuplesOps[Repr, B, C, seq.type] =
new TuplesOps(coll, seq)
List("a"->1, "b"->2).flatMapValues(Seq.fill(_)("x"))
}
And I have this compilation error
[error] /home/yamo/projects/perso/coll213/src/main/scala/example/Aux.scala:24:24: value flatMapValues is not a member of List[(String, Int)]
[error] List("a"->1, "b"->2).flatMapValues(Seq.fill(_)("x"))
Could you help me to make both solution work, if possible ?
I agree, the Custom Collection instructions aren't what they should be.
I find the Factory method a bit easier than the BuildFrom, but I'm still getting used to either/both of them.
import scala.collection.Factory
implicit
class TuplesOps[A,B,CC[x] <: Iterable[x]](val ts: CC[(A,B)]) {
def flatMapValues[C](f: B => IterableOnce[C]
)(implicit fac: Factory[(A,C), CC[(A,C)]]
): CC[(A,C)] =
ts.flatMap{case (a,b) => f(b).iterator.map(x => (a,x))}
.to[CC[(A,C)]](fac)
}
This passes all my simple (minded) tests. It won't work on an Array or an Iterator but then your original Scala 2.12.x version didn't either (for me) so I figured that was okay.

Scala: Create custom OptionT monad from cats for learning

we are creating our own OptionT of cats for understanding, how monads are work and monads transformation flow. While creating our own custom monad getting some of the errors. First thing below is our code:
case class WhateverOpt[W[_], A] (value: W[Option[A]]) {
def map[B] (f: A => B) (implicit M: Monad[W]): WhateverOpt[W, B] =
WhateverOpt(M.map(value)(_.map(f)))
def flatMap[B] (f: A => WhateverOpt[W, B]) (implicit M: Monad[W]): WhateverOpt[W, B] =
WhateverOpt(M.flatMap(value)(optA => optA match {
case Some(v) => f(v).value
}))
}
implicit val optionTMonad = new Monad[Option] {
override def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
override def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa.flatMap(f)
}
val optionResult = for {
user <- WhateverOpt(repository.getUserOption(1))
addres <- WhateverOpt(repository.getAddressOption(user))
} yield addres.city
Below are the points, where we stuck:
How to handle None case in WhateverOpt flatMap method?
When executing the code, getting runtime error:
Error:(26, 12) could not find implicit value for parameter M: usercases.mtransfomer.Monad[scala.concurrent.Future]
addres <- WhateverOpt(repository.getAddressOption(user))
We are not sure about the error because we are creating optionTMonad implicit and by default, all are in the same scope. How can we resolve these two issues?
Update
Full code is available on Github branch https://github.com/harmeetsingh0013/fp_scala/blob/master/src/main/scala/usercases/mtransfomer/Example5.scala
About how to deal with None:
case class WhateverOpt[W[_], A] (value: W[Option[A]]) {
def map[B] (f: A => B) (implicit M: Monad[W]): WhateverOpt[W, B] =
WhateverOpt(M.map(value)(_.map(f)))
def flatMap[B]
(f: A => WhateverOpt[W, B])
(implicit wMonad: Monad[W])
: WhateverOpt[W, B] = {
WhateverOpt(wMonad.flatMap(value) { (oa: Option[A]) =>
oa match {
case None => wMonad.pure(None)
case Some(a) => f(a).value
}
})
}
}
Imagine for a second that W is Future. Then the above code says:
wait until the wrapped value yields a result oa of type Option[A]
If oa turns out to be None, then there is nothing we can do, because we cannot obtain any instances of type A in order to call f. Therefore, immediately return None. The immediately return is the pure-method of the Future-monad, so for the general case we have to invoke wMonad.pure(None).
If oa yields Some(a), we can give this a to f, and then immediately unpack it to get to the value of type W[Option[B]].
Once we have the W[Option[B]] (whether empty or not), we can wrap it into WhateverOpt and return from the flatMap method.
I assume that you wanted to reimplement Monad[Option] just for fun (it's already in the library (the catsStdInstancesForOption thing is a CommutativeMonad), but here is how you could re-build it:
implicit val optionTMonad = new Monad[Option] {
override def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa.flatMap(f)
def pure[A](a: A): Option[A] = Some(a)
def tailRecM[A, B](a: A)(f: (A) => Option[Either[A, B]]): Option[B] = {
f(a) match {
case Some(Left(nextA)) => tailRecM(nextA)(f)
case Some(Right(res)) => Some(res)
case None => None
}
}
}
Notice that 1.0.1 requires to implement pure and tailRecM, and does not provide default implementations for that.
I don't want to say much about the necessary imports for future, but the latest version has cats.instances.future which provides a Monad instance. Check this again, because it seems as if you are using a different version of cats (your version didn't complain because of the missing tailRecM in your Option-monad).
How to handle None case in WhateverOpt flatMap method?
This answer is already explained by #Gabriele Petronella and #Andrey Tyukin with details.
When executing the code, getting runtime error: Error:(26, 12) could
not find implicit value for parameter M:
usercases.mtransfomer.Monad[scala.concurrent.Future] addres <-
WhateverOpt(repository.getAddressOption(user))
This error occurs, because In WhateverOpt constructor we know that our value is W[Option[A]], where Option is already defined and handle by the code, but repository.getUserOption(1) return Future[Option[User]] where Future is handled by generic parameter W and in that, case, we need to define, how to handle monads for Future. For resolving that issue, we need to implement new Monad[Future] rather than, new Monad[Option] as below:
case class WhateverOpt[W[_], A] (value: W[Option[A]]) {
def map[B] (f: A => B) (implicit M: Monad[W]): WhateverOpt[W, B] =
WhateverOpt(M.map(value)(_.map(f)))
def flatMap[B] (f: A => WhateverOpt[W, B]) (implicit M: Monad[W]): WhateverOpt[W, B] =
WhateverOpt(M.flatMap(value)(optA => optA match {
case Some(v) => f(v).value
case None => M.pure(None)
}))
}
implicit val futureMonad = new Monad[Future] {
override def pure[A](a: A): Future[A] = Future.successful(a)
override def map[A, B](fa: Future[A])(f: A => B): Future[B] = fa.map(f)
override def flatMap[A, B](fa: Future[A])(f: A => Future[B]): Future[B] = fa.flatMap(f)
}
val optionResult: WhateverOpt[Future, String] = for {
user <- WhateverOpt(repository.getUserOption(1))
addres <- WhateverOpt(repository.getAddressOption(user))
} yield addres.city
I am not sure about my disription, which I mention in answere, but current my assumptions are this and for me above code is working fine. For a complete example, please click on the GitHub repo, which is mention in the question.
How to handle None case in WhateverOpt flatMap method?
When you flatMap over None you return None. When you flatMap over WhateverOpt[W[_], B] you want to return the pure of it, which in your code would be M.pure(None).
When executing the code, getting runtime error: Error:(26, 12) could not find implicit value for parameter M: usercases.mtransfomer.Monad[scala.concurrent.Future]
addres <- WhateverOpt(repository.getAddressOption(user))
That's a compile-time error (not a runtime one) and it's due to the missing instance of Monad[Future]. In order to get an instance of Monad[Future] in scope with cats, you can do:
import cats.instances.future._
import scala.concurrent.ExecutionContext.Implicits.global
Also, you can avoid declaring your own Monad[Option] by importing it from cats with
import cats.instances.option._

Scala multiple generic parameter data structure typeclass instance

I'm using Scalaz as I'm loving a lot of aspects from Haskell's type class setup in the standard libraries. But exactly this is my current problem. I have a generic data structure with two generic parameters:
case class Parser[T,A](f: T => (T,A))
In Haskell I would implement the Alternative typeclass like this:
newtype Parser t a = Parser { runParser :: t -> (t,a) }
instance Alternative (Parser t) where
...
But how can I do something equivalent in Scala? As far as I know I can't do something like
object Parser {
implicit def ins_Alternative[T] = new Alternative[Parser[T]] {
// ...
}
}
Has anybody an idea how to do this? Thx in advance!
Update:
I've found this:
implicit def eitherMonad[L]: Traverse[Either[L, ?]] with MonadError[Either[L, ?], L] with BindRec[Either[L, ?]] with Cozip[Either[L, ?]] =
new Traverse[Either[L, ?]] with MonadError[Either[L, ?], L] with BindRec[Either[L, ?]] with Cozip[Either[L, ?]] {
def bind[A, B](fa: Either[L, A])(f: A => Either[L, B]) = fa match {
case Left(a) => Left(a)
case Right(b) => f(b)
}
// ...
}
in the Scalaz sources (https://github.com/scalaz/scalaz/blob/series/7.3.x/core/src/main/scala/scalaz/std/Either.scala).
According to this I guess I have to write something like
object Parser {
implicit def ins_Alternative[T] = new Alternative[Parser[T, ?]] {
// ...
}
}
which doesn't compile as the type ? is unknown.
I've found a solution.
implicit def ins_Alternative[T] = new Alternative[({type x[a] = Parser[T, a]})#x] {
override def empty[A]: Parser[T, A] = ???
override def plus[A](a: Parser[T, A], b: => Parser[T, A]): Parser[T, A] = ???
override def point[A](a: => A): Parser[T, A] = ???
override def ap[A, B](fa: => Parser[T, A])(f: => Parser[T, (A) => B]): Parser[T, B] = ???
}

Higher order Functors in scala

So I've been trying to push my intuitions of functors to their limits by defining a higher order functor i.e. a, F that takes 1st order types as type argument, and functions and lifts functions on 1st order types to this higher context in scala something like
trait Functor1[F[_[_]] {
def hmap[X[_], Y[_]] : (X ~> Y) => F[X] => F[Y]
}
I've been trying to define some of the map derivable functions of the normal functor e.g.
trait Functor[F[_]] {
def map[A, B] : (A => B) => F[A] => F[B]
// there's a few more besides this that are map derivable
def distribute[A,B](fab: F[(A, B)]): (F[A], F[B])
}
but I can't write anything that type checks...
I'm just playing but I wonder if anyone else has been down this road that's smarter than me
can a higher order functor be defined in scala ? if not then in haskell ?
Not sure what are your goals, but this typechecks
import scala.language.higherKinds
trait Functor1[F[G[_]]]{
def hmap[X[_], Y[_]]:(X ~> Y) => F[X] => F[Y]
}
case class FId[Z,F[_]](f:F[Z])
implicit def Functor1Id[Z] = new Functor1[({type L[G[_]]=FId[Z,G]})#L]{
def hmap[X[_], Y[_]]:(X ~> Y) => FId[Z,X] => FId[Z,Y]= ???
}
(I added the Z parameter because I wanted to avoid existentials and I had to use the "type lambda" trick)
Do you want to define a map for a "functor of a functor"?
I think I did something similar (here called composition):
case class Comp[F[_],G[_],Z](unComp:F[G[Z]])
implicit def fcomp[F[_], G[_]](implicit ff:Functor[F], fg:Functor[G])=new Functor[({ type abs[A]=Comp[F,G,A]})#abs]{
def fmap[A,B](fga:Comp[F,G,A])(f: A => B):Comp[F,G,B]= Comp(ff.fmap(fga.unComp)(fg.fmap(_)(f)))
}
I've been toying with functors in scala-reggen but I don't think I'm the smart one, as I mainly did it by fumbling around (and checking Scalaz for inspiration)
/** Higher order functor */
trait HFunctor[F[_]] {
def ffmap[G[_]: Functor, A, B](f: A => B): F[G[A]] => F[G[B]]
def hfmap[G[_], H[_]](t: G ~> H): ({type λ[α] = F[G[α]]})#λ ~> ({type λ[α] = F[H[α]]})#λ
}
trait Functor[F[_]] { self =>
def fmap[A, B](f: A => B): F[A] => F[B]
// derived
def map[A, B](x: F[A])(f: A => B): F[B] = fmap(f)(x)
def strengthL[A, B]: A => F[B] => F[(A, B)] = a => f => fmap((x: B) => (a, x))(f)
def strengthR[A, B]: F[A] => B => F[(A, B)] = f => b => fmap((x: A) => (x, b))(f)
def compose[G[_]](implicit e: Functor[G]): Functor[({ type λ[α] = F[G[α]]})#λ] =
new Functor[({ type λ[α] = F[G[α]]})#λ] {
def F = self;
def G = e
def fmap[A, B](f: A => B) = F.fmap(G.fmap(f))
}
}
object Functor {
#inline def apply[F[_]: Functor]: Functor[F] = iev
}
trait Coyoneda[F[_], A] { co =>
type I
def fi: F[I]
def k: I => A
final def run(implicit F: Functor[F]): F[A] = F.fmap(k)(fi)
final def map[B](f: A => B): Coyoneda.Aux[F, B, I] =
Coyoneda(fi)(f compose k)
final def trans[G[_]](phi: F ~> G): Coyoneda[G, A] =
Coyoneda(phi(fi))(k)
}
object Coyoneda {
type Aux[F[_], A, B] = Coyoneda[F, A] { type I = B }
def apply[F[_], B, A](x: F[B])(f: B => A): Aux[F, A, B] =
new Coyoneda[F, A] {
type I = B
val fi = x
val k = f
}
implicit def coyonedaFunctor[F[_]]: Functor[({ type λ[α] = Coyoneda[F, α] })#λ] =
new Functor[({ type λ[α] = Coyoneda[F, α] })#λ] {
def fmap[A, B](f: A => B): Coyoneda[F, A] => Coyoneda[F, B] =
x => apply(x.fi)(f compose x.k)
}
implicit def coyonedaHFunctor: HFunctor[({ type λ[F[_]] = ({ type λ[α] = Coyoneda[F, α] })#λ })#λ] =
new HFunctor[({ type λ[F[_]] = ({ type λ[α] = Coyoneda[F, α] })#λ })#λ] {
def ffmap[G[_]: Functor, A, B](f: A => B): Coyoneda[G, A] => Coyoneda[G, B] = _.map(f)
def hfmap[F[_], G[_]](t: F ~> G): (({ type λ[α] = Coyoneda[F, α] })#λ ~> ({ type λ[α] = Coyoneda[G, α] })#λ) =
new (({ type λ[α] = Coyoneda[F, α] })#λ ~> ({ type λ[α] = Coyoneda[G, α] })#λ) {
def apply[A](x: Coyoneda[F, A]) = x.trans(t)
}
}
def liftCoyoneda[F[_], A](fa: F[A]): Coyoneda[F, A] = apply(fa)(x => x)
def lowerCoyoneda[F[_]: Functor, A](c: Coyoneda[F, A]): F[A] = c.run
}

Implementing Monad.replicateM

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
}