Consider the signature of retrieveUser where retrieving a non-existent user is not modelled as an error, that is, it is modelled as Future[Right[None]]:
def retrieveUser(email: String): Future[Either[Error, Option[User]]]
Does there exist a monad transformer MT such that we can write
(for {
user <- MT(retrieveUser(oldEmail))
_ <- MT(updateUser(user.setEmail(newEmail)))
} {}).run
Using EitherT the best I can do is the following:
EitherT(retrieveUser(oldEmail)).flatMap {
case Some(user) =>
EitherT(updateUser(user.setEmail(newEmail)))
case None =>
EitherT.right(Future.successful({}))
}.run
The problem is that mapping over EitherT(retrieveUser(email)) results in Option[User], instead of unboxed User, which breaks the for-comprehension.
I assume that the order of parameters is the same as in EitherT form Scala Cats: an EitherT[F[_], A, B] is essentially just a wrapper around F[Either[A, B]].
Likewise, OptionT[F, A] is wrapper around F[Option[A]].
Thus,
OptionT[EitherT[Future, Error, ?], A]
is a wrapper around
EitherT[Future, Error, Option[A]]
which is in turn a wrapper around
Future[Either[Error, Option[A]]]
Therefore,
OptionT[EitherT[Future, Error, ?], User](
EitherT[Future, Error, Option[User]](retrieveUser(oldEmail))
)
should typecheck (with the non/kind-projector), and with -Ypartial-unification the types should also be inferred automatically, so you could try to use
OptionT(EitherT(retrieveUser(oldEmail))
inside the for-comprehensions.
Related
I am trying Cats for the first time and am using Scala 3, and I am trying to implement a set of parser combinators for self-pedagogy, however; I am stuck on the definition of the tailRecM function for Monad. I have managed Functor and Applicative just fine.
I have defined my type in question as a function such that:
type Parser[A] = (input: List[Token]) => ParseResult[A]
with corresponding return types as:
type ParseResult[A] = Success[A] | Failure
case class Success[A](value: A, tokens: List[Token])
case class Failure(msg: String, tokens: List[Token])
My current definition of tailRecM is as follows:
#annotation.tailrec
def tailRecM[A, B](init: A)(fn: A => Parser[Either[A, B]]): Parser[B] =
(input: List[Token]) =>
fn(init)(input) match {
case f: Failure => f
case s: Success[Either[A, B]] => s.value match {
case Right(b) => Success(b, s.tokens)
case Left(a) => tailRecM(a)(fn) // won't compile
}
}
If I attempt to build I get "Found: Parsing.Parser[B] Required: Parsing.ParseResult[B]" for tailRecM(a)(fn)
The issue as far as I can tell stems from the fact that my type in question Parser[A] is a function type and not simply a value type? I attempted to ameliorate the issue by modifying the tailRecM recursive call to tailRecM(a)(fn)(input) but then this is obviously not stack safe, and also will not compile.
How can I resolve this issue, and more broadly, how can I implement the Monad typeclass for function types in general?
It's not possible to make tailRecM itself tail-recursive; you need to define a tail-recursive helper method
Here's how the cats library implements tailRecM for Function1
def tailRecM[A, B](a: A)(fn: A => T1 => Either[A, B]): T1 => B =
(t: T1) => {
#tailrec
def step(thisA: A): B =
fn(thisA)(t) match {
case Right(b) => b
case Left(nextA) => step(nextA)
}
step(a)
}
This is because monadic recursion is a form of mutual tail-recursion, where two methods flip back and forth calling each other. The scala compiler can't optimize that. So instead we inline the definition of the monadic part rather than calling flatMap or another method
You need to pass the input again to the tailRecM call
tailRecM(a)(fn)(input)
because tailRecM(a)(fn) returns a Parser, but you need the ParserResult from that returned Parser, as you already did in all other cases.
I'm using Circe and noticed something that i am not so confortable with and would like to understand what is going on under the hood ?
Fundamentally it is not really a circe issue. Also i was just playing with circe around to test few thing. So could have decoded in JsonObject straight but that is beside the point.
val jobjectStr = """{
| "idProperty": 1991264,
| "nIndex": 0,
| "sPropertyValue": "0165-5728"
| }""".stripMargin
val jobject = decode[Json](jobjectStr).flatMap{ json =>
json.as[JsonObject]
}
My issue is with the flapMap signature of Either, contravariance and what is happening here:
We have the following types:
decode[Json](jobjectStr): Either[Error, Json]
json.as[JsonObject]: Decoder.Result[JsonObject]
where circe defines
final type Result[A] = Either[DecodingFailure, A]
and
sealed abstract class DecodingFailure(val message: String) extends Error {
Now the signature of flatMap in either is:
def flatMap[A1 >: A, B1](f: B => Either[A1, B1]): Either[A1, B1]
In other words, talking only about type it is like my code is doing
Either[Error, Json] flatMap Either[DecodingFailure, JsonObject]
Hence my issue is: DecodingFailure >: Error is not true
And Indeed the type of the full expression is:
decode[Json](jobjectStr).flatMap{ json =>
json.as[JsonObject]
}: Either[Error, JsonObject]
Hence i'm confused, because my understanding is that the type of the first Parameter of Either is Contravariant in the flatMap Signature. Here there seems to be some wierd least upper bound inferencing going on ... But i am not sure why or if it is even the case.
Any explanation ?
This really isn't a variance issue. A1 >: A is just telling us that the result type, A1, might have to be a super-type of the received type, A, if the compiler has to go looking for a least upper bound (the LUB). (The use of A1 in the f: B => ... description is, I think, a bit confusing.)
Consider the following:
class Base
class SubA extends Base
class SubB extends Base
Either.cond(true, "a string", new SubA)
.flatMap(Either.cond(true, _, new SubB))
//res0: scala.util.Either[Base,String] = Right(a string)
Notice how the result is Either[Base,String] because Base is the LUB of SubA and SubB.
So first of all, we need to understand that the compiler will always try to infer types that allow compilation. The only real way to avoid something to compile is to use implicits.
(not sure if this is part of the language specification, or a compiler implementation detail, or something common to all compilers, or a bug or a feature).
Now, let's start with a simpler example List and ::.
sealed trait List[+A] {
def ::[B >: A](b: B): List[B] = Cons(b, this)
}
final case class Cons[+A](head: A, tail: List[A]) extends List[A]
final case object Nil extends List[Nothing]
So, assuming the compiler will always allow some code like x :: list will always compile. Then, we have three scenarios:
x is of type A and list is a List[A], so it is obvious that the returned value has to be of type List[A].
x is of some type C and list is a List[A], and C is a subtype of A (C <: A). Then, the compiler simply upcast x to be of type A and the process continues as the previous one.
x is of some type D and list is a List[A], and D is not a subtype of A. Then, the compiler finds a new type B which is the LUB between D and A, the compiler finally upcast both x to be of type B and list to be a List[B] (this is possible due covariance) and proceeds like the first one.
Also, note that due to the existence of types like Any and Nothing there is "always" a LUB between two types.
Now let's see Either and flatMap.
sealed trait Either[+L, +R] {
def flatMap[LL >: L, RR](f: R => Either[LL, RR]): Either[LL, RR]
}
final case class Left[+L](l: L) extends Either[L, Nothing]
final case clas Right[+R](r: R) extends Either[Nothing, R]
Now, assuming my left side is an Error, I feel this behaviour of returning the LUB between the two possible lefts is the best, since at the end I would have the first error, or the second error or the final value, so since I do not know which of the two errors it was then that error must be of some type that encapsulates both possible errors.
I'm trying to define an abstract algebra that will allow me to defer choosing what Monad I will use to wrap an effectful operation (IO, Task, Future, etc) until I run the program.
trait MyAlg[F[_]]
def isValid(v: int): F[Boolean]
def getElements(): F[List[Int]]
def filterValidElements(vs: F[List[Int]]): F[List[Int]]
Imagine that I need to do something possibly side-effecting in isValid, like check the db.
What would be nice is if I could leave isValid and getElements abstract --- so that for example one implementation could connect to a database and another could refer to a mock for testing --- but define a generic filterValidElements so I don't need to re-impliment the same function for both cases. Something like this:
def filterValidElements(es: F[List[Int]]]): F[List[Int]] =
es.map(
elems => elems.map(
e => (e, isValid(e))).collect{
case (e, F(true)) => e
})
However,F is generic, so it doesn't provide map and doesn't have a constructor.
Of course, I can't explicity set F to be a Monad, for example like
trait MyAlg[F: cats.Monad]
because traits cannot have type parameters with context bounds.
Is there any way to write my filterValidElements function, leaving isValid abstract and F generic?
I am pretty new with this style, so I may be going about this entirely the wrong way.
Try to add implicit parameters specifying that you can do map (i.e. Functor) and pure aka point (i.e. InvariantMonoidal). For example you can make it Applicative or Monad.
import cats.{Functor, InvariantMonoidal}
import cats.syntax.functor._
import scala.language.higherKinds
trait MyAlg[F[_]] {
def isValid(v: Int): F[Boolean]
def getElements(): F[List[Int]]
def filterValidElements(es: F[List[Int]])(implicit functor: Functor[F], im: InvariantMonoidal[F]): F[List[Int]] =
es.map(
elems => elems.map(
e => (e, isValid(e))).collect{
case (e, fb) if fb == im.point(true) => e
})
}
an example use case:
def div2(i: Int): Validation[String, Int] =
if (i%2 == 0) Validation.success(i/2)
else Validation.failure("odd")
def div4(i: Int) = for {
a <- div2(i)
b <- div2(a)
} yield b
error: Unable to unapply type scalaz.Validation[String,Int] into a type constructor of kind M[_] that is classified by the type class scalaz.Bind
I guess the error is caused by the compiler can't find a Monad instance for Validation[String, Int]
I can make one for myself, like:
object Instances {
implicit def validationMonad[E] = new Monad[({type L[A] = Validation[E, A]})#L] {
override def point[A](a: => A) =
Validation.success(a)
override def bind[A, B](fa: Validation[E, A])(f: A => Validation[E, B]) =
fa bind f
}
}
but why doesn't Validation have it already? after all, Validation already has the bind method defined.
moreover, I can't have import Validation._ and import Instances._ together anymore (this took me looong to figure out...), because of another complicated error...
ambiguous implicit values: something like both validationMonad (my instance), and method ValidationInstances1 in trait ValidationInstances2... both match some Functor of Validation...
should I modify the source of scalaz? or I'm completely missing something~?
please help~
I'm using scalaz 7.0.0-M2
As discussed in the Scalaz group, the problem seems to be that ap would accumulate errors whereas (pseudo-)monadic composition would only operate on the value part of Validation.
Therefore, one cannot be expressed in terms of the other and thus no monad instance exists for Validation.
The issue is that the applicative functor as implied by the monad does not equal the actual applicative functor
Why does this code not type check?
def foo: Either[String, List[Int]] = {
val x = null: Either[String, String]
x match {
case l # Left(_) => l
case Right(_) => Right(List(3))
}
}
Specifically, why can't/doesn't the compiler reify the type of Left[A,X] and Either[A,B]?
This happened in scala 2.8.2 and scala 2.9.2
There is a genuine conflict here:
Left[String, String] <: Either[String, List[Int]]
is not true. Left is typed on both left and right parameters, and even though there is no actual difference between the two (so casting would be safe), this is not what you have told the compiler. So, of course, it will complain.
There are other weaknesses in type inference in pattern matching, but this is not one of them.
Edit: one can imagine an alternate singly-parameterized implementation of Left in which
Left[String] <: Either[String, Nothing] <: Either[String, List[Int]]
which would throw away type information. Methods like swap would be tricker to use, but it would allow the pattern given by the OP. However, the type-preserving form was used in the standard implementation in Scala.