如何 return 值与嵌套 Reader 单子与猫?

How to return values with nested Reader monads with cats?

有没有一种方法可以避免两次调用“运行”方法并从主方法中只调用一次,或者这是在嵌套阅读器中调用的正确方法?

  case class Dependencies(showService: ShowService, sumService: SumService)

  class ShowService {
    def show(s: String): IO[Unit] = IO {println(s)}
  }

  class SumService() {
    def sum(a: Int, b: Int): Reader[Dependencies, IO[Int]] = Reader {_ => IO {a + b} }
  }

  object ModuleA {
    def sumAndShow: ReaderT[IO, Dependencies, Unit] = for {
      x <- ReaderT[IO, Dependencies, Int] (deps => deps.sumService.sum(10, 10).run(deps))
      r <- ReaderT[IO, Dependencies, Unit] (deps => deps.showService.show(x.toString))
    } yield r
  }
  
  override def run(args: List[String]): IO[ExitCode] = {
    val dependencies = Dependencies(new ShowService, new SumService)
    ModuleA.sumAndShow.run(dependencies) *> IO(ExitCode.Success)
  }

我不确定您为什么选择以这种方式定义您的服务,但如果您的问题是避免在 sumAndShow 中调用 run,您可以解除 Reader/IOlift/liftF 组合成 ReaderTs 并用 ReaderT.ask:

组成它们
def sumAndShow: ReaderT[IO, Dependencies, Unit] =
  for {
    deps <- ReaderT.ask[IO, Dependencies]
    x <- deps.sumService.sum(10, 10).lift[IO].flatMap(ReaderT.liftF)
    r <- ReaderT.liftF(deps.showService.show(x.toString))
  } yield r

具有 Cats/Cats 效果的现有类型类约束的替代泛型实现,以及如何将 newtype 用于替代类型类实例:

import cats.implicits._
import cats.effect._
import cats.effect.std.Console
import cats.{Semigroup, Show}
import io.estatico.newtype.macros.newtype


object Main extends IOApp {
  @newtype case class MInt(value: Int)
  object MInt {
    implicit val multiplicativeSemigroup: Semigroup[MInt] =
      deriving(Semigroup.instance(_ * _))
    implicit val show: Show[MInt] = deriving
  }

  def sumAndShow[F[_]: Console, A: Show: Semigroup](a: A, b: A): F[Unit] =
    Console[F].println(a |+| b)

  override def run(args: List[String]): IO[ExitCode] =
    for {
      _ <- sumAndShow[IO, Int](10, 10) //20

      //you can also "inject" default/custom typeclass "dependencies" explicitly
      _ <- sumAndShow[IO, Int](10, 10)(Console[IO], Show[Int], Semigroup.instance(_ * _)) //100

      //custom typeclass instance with newtype
      _ <- sumAndShow[IO, MInt](MInt(10), MInt(10)) //100

      _ <- sumAndShow[IO, String]("Hello", "World") //HelloWorld
    } yield ExitCode.Success
}