2

I'm trying to use an Either as the result of an algebra using Free monad, like the following code


  ///// Command
  sealed trait Command[A]

  type Result[A] = Either[Exception, A]

  object Command {
    case class Tell(line: String) extends Command[Result[Unit]]

    case class Ask(line: String) extends Command[Result[String]]

  }
  type App[A] = EitherK[Command, Log, A]

  def program(implicit L: LogOps[App],
              C: CommandOps[App]): Free[App, Unit] =
    for {
      _ <- L.show("start <ask>")
      name <- C.ask("What's your name?")
      _ <- L.show("start <tell>")
      _ <- C.tell(s"Hi <$name>, nice to meet you!")
      _ <- L.show("done.")
    } yield ()

...

the problem is that the name is an Either, so I got the following output

L--- start <ask>
What's your name?
George
L--- start <tell>
Hi <Right(George)>, nice to meet you!
L--- done.

Any idea?

Thanks

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
marc0x71
  • 43
  • 6

1 Answers1

2

Solution found in this link

Scala Free Monads with Coproduct and monad transformer

I had to define a function like following

def liftFE[F[_], T[_], A, B](f: T[Either[A, B]])(implicit I: InjectK[T, F]): EitherT[Free[F, *], A, B] = EitherT[Free[F, *], A, B](Free.liftF(I.inj(f)))

and use it instead of Free.inject like the follow

  class CommandOps[F[_]](implicit I: InjectK[Command, F]) {

    import Command.{Ask, Tell}

    def tell(line: String): EitherT[Free[F, *], Exception, Unit] =
      liftFE(Tell(line))

    def ask(line: String): EitherT[Free[F, *], Exception, String] =
      liftFE(Ask(line))
  }

and change also 'program' result type

  def program(implicit L: LogOps[App],
              C: CommandOps[App]): EitherT[Free[App, *], Exception, Either[Exception, Unit]] =
marc0x71
  • 43
  • 6