I'm playing with monad transformers in scalaz. I'm trying to stack together a Writer on the top of Reader with the underlying Id monad. For combining them I'm using MonadReader and MonadWriter type classes.
I managed to compile and run the following code sample without the writer (i.e. with the Reader monad, i.e. ReaderT[Id.Id, String, A]). When adding a WriterT to the stack, I get the compilation error:
Gist.scala:10: could not find implicit value for parameter F: scalaz.MonadReader[Gist.R,String]
val MR = MonadReader[R, String]
^
How can I obtain an instance of MonadReader for my transformer stack? Do I have to make use of ReaderWriterStateT or is there another way?
Full code:
import scalaz.{Id, MonadListen, MonadReader, ReaderT, WriterT}
object Gist {
import scalaz.std.list._
import scalaz.syntax.monad._
type P[A] = ReaderT[Id.Id, String, A]
type R[A] = WriterT[P, List[String], A]
val MR = MonadReader[R, String]
val MW = MonadListen[R, List[String]]
def apply: R[String] = MR.ask >>= { greeting =>
MW.tell(List(s"greeting $greeting")) >>= { _ =>
MW.point(s"Hello $greeting")
}
}
}
I'm not entirely sure why Scalaz doesn't provide this instance (or MonadReader instances for similar monad transformers), but I'd guess the answer has something to do with the fact that WriterTInstanceN already goes past 11 and adding in MonadReader would just make things even more of a mess.
You could dig around in Scalaz's GitHub issues (or even ask on the IRC channel if you have the stomach for that kind of thing), but I'm not sure the answer matters all that much.
You can pretty straightforwardly port the instance from Haskell's mtl:
instance (Monoid w, MonadReader r m) => MonadReader r (Strict.WriterT w m) where
ask = lift ask
local = Strict.mapWriterT . local
reader = lift . reader
Which translated into Scala looks like this:
import scalaz.{ MonadReader, MonadTrans, Monoid, WriterT }
import scalaz.syntax.monad._
implicit def monadReaderForWriterT[F[_], I, W](implicit
F: MonadReader[F, I],
W: Monoid[W]
): MonadReader[WriterT[F, W, ?], I] = new MonadReader[WriterT[F, W, ?], I] {
def ask: WriterT[F, W, I] = MonadTrans[WriterT[?[_], W, ?]].liftM(F.ask)
def local[A](f: I => I)(fa: WriterT[F, W, A]): WriterT[F, W, A] =
fa.mapT(F.local(f))
def point[A](a: => A): WriterT[F, W, A] = a.point[WriterT[F, W, ?]]
def bind[A, B](fa: WriterT[F, W, A])(
f: A => WriterT[F, W, B]
): WriterT[F, W, B] = fa.flatMap(f)
}
Note that I'm using kind-projector, since the type lambda version would be more like four or five times as long as the Haskell version instead of just three times.
Once you've defined this instance, you can write the following:
import scalaz.{ Id, MonadListen, ReaderT }
import scalaz.std.list._
type P[A] = ReaderT[Id.Id, String, A]
type R[A] = WriterT[P, List[String], A]
val MR = MonadReader[R, String]
val MW = MonadListen[R, List[String]]
def apply: R[String] = MR.ask >>= { greeting =>
MW.tell(List(s"greeting $greeting")) >>= { _ =>
MW.point(s"Hello $greeting")
}
}
Related
I tried to write a Kleisli.ap function.
final case class Kleisli[F[_], -A, B](run: (A) ⇒ F[B]) extends Product with Serializable
def ap[C, D, AA <: A](f: Kleisli[F, AA, C])(implicit F: Apply[F], ev: As[B, (C) ⇒ D]): Kleisli[F, AA, D]
but
import cats._
import cats.implicits._
import cats.data._
val x: Kleisli[Option,String,Int] = Kleisli(_ => Some(1))
val y: Kleisli[Option,String,Double] = Kleisli(_ => Some(1.0))
val kleisliAp: Kleisli[Option,String,Double] = x.ap(y)
// No implicits found for parameter ev: As[Int, Double => D_]
I saw this error code and looked for a way to create an instance of As[A,B] but could not find one.
Please let me know if you know how to solve this problem.
ap is the wrong way to combine the two objects you have.
ap requires an F[A] and an F[A => B]. You have an F[A] and an F[B]
Instead, use mapN
(x, y).mapN { (int, double) => ??? }
Additionally, ap is considered bad style in scala FP. The shape of it is really not suited to scala; it's there because it's part of the foundation of Apply but mapN is the idiomatic way to compose objects applicatively
let's say I have:
trait Get[F[_], A, B]{
def get(a:A): F[B]
}
I want to be able to map over the result type B, ie I want to be able to do:
val getFoo: Get[IO, String, Foo] = ???
val foo2Bar: Foo => Bar = ???
val getBar: Get[IO, String, Bar] = getFoo.map(foo2Bar)
I understand that I should implement a Functor instance for Get but I am struggling as I don't know what type signature to use.
I tried the following:
implicit val functor:Functor[Get] = ???
implicit val functor: Functor[Lambda[(F[_], K, A) => Get[F, K, A]]] = ???
but they don't seem to be of the right type as I can't seem to use the functor syntax extension as illustrated at the top. What is the right way of expressing the type here? What would be the equivalent type be if I use the kind-projector plugin?
Try
import cats.syntax.functor._
implicit def functor[F[_]: Functor, A]: Functor[Get[F, A, ?]] = new Functor[Get[F, A, ?]] {
override def map[B, B1](fa: Get[F, A, B])(f: B => B1): Get[F, A, B1] = a => fa.get(a).map(f)
}
I am working with cats and I want to transform my val x: State[A, B] to StateT[IO, A, B]. Note: IO is from cats-effects.
How to do this elegantly?
Try mapK in combination with cats.arrow.FunctionK.lift:
x.mapK(lift(IO.eval))
Full compilable code snippet:
import cats.effect.IO
import cats.data.{State, StateT}
import cats.arrow.FunctionK.lift
object InjectIdIO {
def i[S, V](x: State[S, V]): StateT[IO, S, V] = x.mapK(lift(IO.eval))
}
This works because State[S, A] is actually StateT[Eval, S, A], and you want to replace the Eval by IO - this is what the mapK is usually for.
Another alternative with kind-projector:
x.mapK(Lambda[Eval ~> IO](IO.eval(_)))
Try
def liftState[A, B](state: State[A, B]): StateT[IO, A, B] =
StateT[IO, A, B] { s => IO.eval(state.run(s)) }
for example
val x: State[Int, String] = State(int => (int, "foo"))
liftState(x)
Since Free is not a monad instance in Scalaz 7.1.5, I can't use useful method defined in Applicative, Apply and so on.
/* ref - http://tpolecat.github.io/assets/sbtb-slides.pdf */
import Free._, Coyoneda._
type ResultSetIO[A] = FreeC[ResultSetOp, A]
val next : ResultSetIO[Boolean] = liftFC(Next)
def getString(index: Int): ResultSetIO[String] = liftFC(GetString(index))
def getInt(index: Int) : ResultSetIO[Int] = liftFC(GetInt(index))
def close : ResultSetIO[Unit] = liftFC(Close)
// compile errors
def getPerson1: ResultSetIO[Person] =
(getString(1) |#| getInt(2)) { Person(_, _)}
def getNextPerson: ResultSetIO[Person] =
next *> getPerson
def getPeople(n: Int): ResultSetIO[List[Person]] =
getNextPerson.replicateM(n) // List.fill(n)(getNextPerson).sequence
the erorr message is,
Error:(88, 19) value |#| is not a member of free.JDBC.ResultSetIO[String]
(getString(1) |#| getInt(2)) { Person(_, _)}
^
Error:(91, 10) value *> is not a member of free.JDBC.ResultSetIO[Boolean]
next *> getPerson
^
Error:(94, 19) value replicateM is not a member of free.JDBC.ResultSetIO[free.Person]
getNextPerson.replicateM(n) // List.fill(n)(getNextPerson).sequence
^
Should I implement monad instance for Free?
implicit val resultSetIOMonadInstance = new Monad[ResultSetIO] {
override def bind[A, B](fa: ResultSetIO[A])(f: (A) => ResultSetIO[B]): ResultSetIO[B] =
fa.flatMap(f)
override def point[A](a: => A): ResultSetIO[A] =
Free.point[CoyonedaF[ResultSetOp]#A, A](a)
}
Or, am I missing something? (e.g import)
This is just the Scala compiler being fussy about type aliases. You have two choices (or at least two choices—there are probably other reasonable workarounds). The first is to break down the type alias slightly differently. Instead of this:
type ResultSetIO[A] = FreeC[ResultSetOp, A]
You write this:
type CoyonedaResultSetOp[A] = Coyoneda[ResultSetOp, A]
type ResultSetIO[A] = Free[CoyonedaResultSetOp, A]
And then Monad[ResultSetIO] will compile just fine. You will need one extra import for |#|, *>, and replicateM:
import scalaz.syntax.applicative._
The other option is to leave the FreeC as it is and define the monad instance yourself, since scalac won't find it for you. Fortunately you can do this a little more simply than writing it out as you propose:
implicit val monadResultSetIO: Monad[ResultSetIO] =
Free.freeMonad[({ type L[x] = Coyoneda[ResultSetOp, x] })#L]
I prefer the first approach, but it doesn't really matter which you choose.
Here's a simplified complete working example for the sake of convenience:
sealed trait ResultSetOp[A]
case object Next extends ResultSetOp[Boolean]
case class GetString(index: Int) extends ResultSetOp[String]
case class GetInt(index: Int) extends ResultSetOp[Int]
case object Close extends ResultSetOp[Unit]
import scalaz.{ Free, Coyoneda, Monad }
import scalaz.syntax.applicative._
type CoyonedaResultSetOp[A] = Coyoneda[ResultSetOp, A]
type ResultSetIO[A] = Free[CoyonedaResultSetOp, A]
val next: ResultSetIO[Boolean] = Free.liftFC(Next)
def getString(index: Int): ResultSetIO[String] = Free.liftFC(GetString(index))
def getInt(index: Int): ResultSetIO[Int] = Free.liftFC(GetInt(index))
def close: ResultSetIO[Unit] = Free.liftFC(Close)
case class Person(s: String, i: Int)
def getPerson: ResultSetIO[Person] = (getString(1) |#| getInt(2))(Person(_, _))
def getNextPerson: ResultSetIO[Person] = next *> getPerson
def getPeople(n: Int): ResultSetIO[List[Person]] = getNextPerson.replicateM(n)
This will compile just fine with 7.1.5.
For the sake of completeness, there's a third way, which is to define some Unapply machinery to help the compiler find instances for the FreeC version (Rob Norris is responsible for this code, which I've just de-kind-projected):
implicit def freeMonadC[FT[_[_], _], F[_]](implicit
ev: Functor[({ type L[x] = FT[F, x] })#L]
) = Free.freeMonad[({ type L[x] = FT[F, x] })#L]
implicit def unapplyMMFA[TC[_[_]], M0[_[_], _], M1[_[_], _], F0[_], A0](implicit
TC0: TC[({ type L[x] = M0[({ type L[x] = M1[F0, x] })#L, x] })#L]
): Unapply[TC, M0[({ type L[x] = M1[F0, x] })#L, A0]] {
type M[X] = M0[({ type L[x] = M1[F0, x] })#L, X]
type A = A0
} = new Unapply[TC, M0[({ type L[x] = M1[F0, x] })#L, A0]] {
type M[X] = M0[({ type L[x] = M1[F0, x] })#L, X]
type A = A0
def TC = TC0
def leibniz = Leibniz.refl
}
This allows you to use FreeC without defining monad instances every time. I still think just giving up on FreeC and using Free is a better idea, though.
I have already understood how to create a Functor on my own case class when its parameters are of the same type A.
case class MyCaseClass[A](a: A, b: A)
val local = MyCaseClass[String]("One", "Two")
implicit val myCaseClassFunctor = new Functor[MyCaseClass]{
def map[A, B](fa: MyCaseClass[A])(f: A => B) = MyCaseClass(f(fa.a), f(fa.b))
}
val F = Functor[MyCaseClass]
val res = F.map(local)(_ + ".")
println(res)
In real life problems, a case class isn't going to be formed by parameters of the same type but different ones.
If the case clase gets to be something as simple as
case class MyCaseClass[A, B](a: A, b: B)
Is it possible to build a Functor for it?
My guess is I can't ever since the definition of map is quite clear with repect to its types parameters
def map[A, B]
But I have to ask ever since this is my first time programming a Functor.
For a class with two parameters there are two Functors possible: one that maps the first field and another one that maps the second field. While this is the solution, I would recommend to define a Bifunctor because it is more general:
implicit val bifunctor = new Bifunctor[MyCaseClass] {
/** `map` over both type parameters. */
def bimap[A, B, C, D](fab: MyCaseClass[A, B])(f: A => C, g: B => D): MyCaseClass[A, B] =
MaCaseClass(f(fab.a), g(fab.b))
}
Having a Bifunctor instance you can easily get a Functor for either the left of the right parameter:
implicit def functor[X] = bifunctor.leftFunctor[X]
// or
implicit def functor[X] = bifunctor.rightFunctor[X]
Functor requires types with a single type parameter, yes, but you can use so-called type lambdas:
implicit def myCaseClassFunctor[C] = new Functor[({type f[X] = MyCaseClass[C, X]})#f]{
def map[A,B](fa: MyCaseClass[C,A])(f:A=>B) = MyCaseClass(fa.a, f(fa.b))
}