WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Can't migrate from v0.7: StateT[EitherT, ...], ...] vs. EitherT[StateT, ...], ...] #305

@marcinzh

Description

@marcinzh

Cats-MTL v0.7.1 allows both arrangements.

Cats-MTL v1.1.1 case works only when EitherT is on the top.

Using: cats-mtl v0.7.1

https://scastie.scala-lang.org/vIEWTZkrTlGyel2jBiwRoA

import cats.{Monad, Id}
import cats.data.{StateT, EitherT}
import cats.implicits._
import cats.mtl.{MonadState, FunctorRaise}
import cats.mtl.implicits._

object Main extends App {
  def computation[F[_]: Monad: MonadState[*[_], Int]: FunctorRaise[*[_], String]](a: Int): F[Int] = a.pure[F]
  type MyEither[A] = EitherT[Id, String, A]
  type MyState[A] = StateT[MyEither, Int, A]
  val result = computation[MyState](42).run(0).value  // <====== NO ERROR
  println(result)
}

Using: cats-mtl v1.1.1

https://scastie.scala-lang.org/bZE05pflSnKOjpPiGmksjg

import cats.{Monad, Id}
import cats.data.{StateT, EitherT}
import cats.implicits._
import cats.mtl.{Stateful, Raise}
import cats.mtl.implicits._

object Main extends App {
  def computation[F[_]: Monad: Stateful[*[_], Int]: Raise[*[_], String]](a: Int): F[Int] = a.pure[F]
  type MyEither[A] = EitherT[Id, String, A]
  type MyState[A] = StateT[MyEither, Int, A]
  val result = computation[MyState](42).run(0).value  //  <======  ERROR
  println(result)
}

Compiler output

Could not find an implicit instance of Raise[Main.MyState, String]. If you have
a good way of handling errors of type String at this location, you may want
to construct a value of type EitherT for this call-site, rather than Main.MyState.
An example type:

  EitherT[Main.MyState, String, *]

This is analogous to writing try/catch around this call. The EitherT will
"catch" the errors of type String.

If you do not wish to handle errors of type String at this location, you should
add an implicit parameter of this type to your function. For example:

  (implicit fraise: Raise[Main.MyState, String])

Manually defining the missing Raise instance using def raise(e) = StateT.liftF(EitherT.leftT(e)) makes it work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions