免费monad翻译只有副作用

时间:2018-06-13 18:34:34

标签: scala-cats

我需要编写免费的monad解释器,它只执行有效的操作但不返回任何结果。对于免费的应用程序,我使用了MyAction ~> Const[Unit, ?]签名的解释器,并使用foldMap函数调用它。但是Const没有monad实例。 Id不适合,因为它需要返回实际值(评估嵌入式语言)。我应该编写自己的monad实例,类似于Id,但没有潜在的价值,或者有一种更方便的方法来创建不产生任何值的解释器?

1 个答案:

答案 0 :(得分:0)

“不产生任何价值”是什么意思?这是Free monad的示例,其中的解释器不返回任何内容,但会执行某些操作。

import cats.{Id, ~>}
import cats.effect.{ExitCode, IO, IOApp}
import cats.free.Free
import cats.free.Free.liftF


object Main extends IOApp {

  // define algebra
  sealed trait LaunchMissilesA[A]
  case class LaunchMissileType1(arg: Int) extends LaunchMissilesA[Unit]
  case class LaunchMissileType2(arg: String) extends LaunchMissilesA[Unit]

  // define Free type
  type LaunchMissiles[A] = Free[LaunchMissilesA, A]

  // smart constructors
  def launchMissileType1(arg: Int): LaunchMissiles[Unit] = liftF[LaunchMissilesA, Unit](LaunchMissileType1(arg))
  def launchMissileType2(arg: String): LaunchMissiles[Unit] = liftF[LaunchMissilesA, Unit](LaunchMissileType2(arg))

  // final program
  def launchVariousMissiles: LaunchMissiles[Unit] =
    for {
      _ <- launchMissileType1(1)
      _ <- launchMissileType2("str2")
    } yield ()

  // interpreter #1: IO
  def ioMissileLauncher: LaunchMissilesA ~> IO = new (LaunchMissilesA ~> IO) {
    override def apply[A](fa: LaunchMissilesA[A]): IO[A] = fa match {
      case LaunchMissileType1(arg) =>
        IO(println(s"[IO] launching Int missile of type 1: $arg").asInstanceOf[A])
      case LaunchMissileType2(arg) =>
        IO(println(s"[IO] launching String missile of type 2: $arg").asInstanceOf[A])
    }
  }

  // interpreter #2: Id
  def idMissileLauncher: LaunchMissilesA ~> Id = new (LaunchMissilesA ~> Id) {
    override def apply[A](fa: LaunchMissilesA[A]): Id[A] = fa match {
      case LaunchMissileType1(arg) =>
        println(s"[Id] launching Int missile of type 1: $arg").asInstanceOf[A]
      case LaunchMissileType2(arg) =>
        println(s"[Id] launching String missile of type 2: $arg").asInstanceOf[A]
    }
  }

  // end of the world
  override def run(args: List[String]): IO[ExitCode] = for {
    _ <- launchVariousMissiles.foldMap(ioMissileLauncher)
    _ <- IO(launchVariousMissiles.foldMap(idMissileLauncher))
  } yield ExitCode(0)
}