Scala cats. How do I write Kleisli[F[_],A,B].ap? - scala

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

Related

Scala converting List of case class to List of another case class

case class student1(name :String, marks :Long)
case class student2(studentName:String, marks:Long)
val mylist:List[student1] = List( student1("a",100) , student1("b",200))
How can I convert mylist into List[student2] in more elegant way than this?
val res: List[student2] = mylist.map(s => student2(s.name,s.marks))
You could add an auxiliary constructor.
case class student2(studentName:String, marks:Long) {
def this(s:student1) = this(s.name, s.marks)
}
. . .
val res: List[student2] = mylist.map(new student2(_))
Or you could just do a pattern match, but for that you really should capitalize your class names.
val res: List[Student2] =
mylist.map{case Student1(n,m) => Student2(n,m)}
First of all, please name your classes in CapitalCamelCase. So Student1 and Student2.
Now, If you have two exactly same case classes like in this case, you can easily convert between them without using any libraries.
val myList2: List[Student2] =
mylist.map(s => Student2.tupled(Student1.unapply(s).get))
This will work for any two case classes A and B which are similar in strcuture.
#sarveshseri's (#esse's) solution seems to be the simplest one in Scala 2 (Scala 3). The following solutions using libraries are harder but more flexible.
If you have the only such transormation I'd stay with your approach or with the one suggested by #wvh.
If you have many such transformations consider to use one of data manipulating libraries.
For example Chimney
import io.scalaland.chimney.dsl._
val res: List[student2] = mylist.map(
_.into[student2]
.withFieldRenamed(_.name, _.studentName)
.transform
)
or Shapeless
import shapeless.{Generic, HList}
trait Convert[A, B] {
def apply(a: A): B
}
object Convert {
implicit def mkConvert[A <: Product, B <: Product, L <: HList](implicit
genericA: Generic.Aux[A, L],
genericB: Generic.Aux[B, L]
): Convert[A, B] = a => genericB.from(genericA.to(a))
}
implicit class ConvertOps[A](val a: A) extends AnyVal {
def to[B](implicit convert: Convert[A, B]): B = convert(a)
}
val res: List[student2] = mylist.map(_.to[student2])
Also look at Monocle or Quicklens.
If you are using Scala 3 (aka dotty), the following code works:
scala> import scala.deriving.Mirror
scala> mylist.map(summon[Mirror.Of[student2]].fromProduct)
val res1: List[student2] = List(student2(a,100), student2(b,200))

Functor implementation for types with more than one type

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)
}

Cats instances for Some and None et al

In Scala 2.13 and Cats, the following works fine:
import cats.implicits._
Traverse[Option]
However the following fails:
import cats.implicits._
Traverse[Some]
I would like for the latter to work, not only for Traverse of Option subclasses, but for any type that has a parent that there exists a given typeclass for.
I have tried creating a method with implicit proof <:< but can't quite get it to work.
If you really understand what you do you can define necessary instance manually (when it exists).
Some is isomorphic to Id.
implicit val someTraverse: Traverse[Some] = new Traverse[Some] {
override def traverse[G[_]: Applicative, A, B](fa: Some[A])(f: A => G[B]): G[Some[B]] = f(fa.value).map(Some(_))
override def foldLeft[A, B](fa: Some[A], b: B)(f: (B, A) => B): B = f(b, fa.value)
override def foldRight[A, B](fa: Some[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = f(fa.value, lb)
}
Generally this is not possible. If F is a functor and G[T] <: F[T] for all T then G is not necessarily a functor.
Calling generic function with Functor using subclass (cats/scalaz)
Also sometimes you can derive type classes using kittens.
Why can find `Functor` instance for Tree but not for Branch or Leaf?

How to stack ReaderT and WriterT transformers in scalaz?

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")
}
}

How to use lift from ToFunctorOps

ToFunctorOps defines a lift method via the ToLiftV implicit, but I can't seem to make it find my functor instances:
import scalaz.std.option._
import scalaz.syntax.functor._
import scalaz.syntax.id._
import scalaz.syntax.std.option._
def inc(x: Int) = x + 1
1.some |> (inc _).lift
<console>:16: error: could not find implicit value for parameter F: scalaz.Functor[F]
1.some |> (inc _).lift
The functor instance for option is visible but the compiler can't seem to find it. Any suggestions as to how I can fix this?
I don't understand exactly why this isn't working (and I've just asked a follow-up question about the part I don't understand), but I can offer three workarounds.
The first makes no sense to me and requires some deeper changes to your code and clunky syntax, so I'll only mention it in passing.
The second is to import the appropriate FunctorSyntax implicits (as opposed to the ToFunctorOps ones that aren't working properly):
scala> val of = implicitly[scalaz.Functor[Option]]
of: scalaz.Functor[Option] = scalaz.std.OptionInstances$$anon$1#377d4c39
scala> import of.functorSyntax._
import of.functorSyntax._
scala> 1.some |> (inc _).lift
res0: Option[Int] = Some(2)
But this requires you to import these implicits for every individual Functor you want to use them with, and isn't much better than just writing of lift inc.
The last requires a little more code but is more satisfying. You need the following new syntax trait, with a myLift method modeled of the lift in Function2Ops:
trait MyFunction1Syntax[A, R] extends scalaz.syntax.Ops[A => R] {
def myLift[F[_]](implicit F: scalaz.Functor[F]) = F lift self
}
implicit def toMyFunction1Syntax[A, R](f: A => R) =
new MyFunction1Syntax[A, R] { def self = f }
And now you can write the following:
scala> 1.some |> (inc _).myLift
res3: Option[Int] = Some(2)
It might be worth bringing this issue up on the Scalaz mailing list.
Your problem can be easily resolved like this
import scalaz.syntax.std.option._
import scalaz.std.option._
import scalaz.syntax.id._
implicit def liftIt[F[_], A, B](f: A => B)(implicit F: Functor[F]): F[A] => F[B] =
F lift f
def inc(x: Int) = x + 1
2.some |> inc
The issue came from a LiftV trait used in FunctorSyntax. Frankly, I doubt it could have been useful for someone. In order to work, it has to be explicitly typed:
import scalaz.syntax.functor._
val f: LiftV[Option, Int, Int] = (inc _)
2.some |> f.lift