如何 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
/IO
与 lift
/liftF
组合成 ReaderT
s 并用 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
}
有没有一种方法可以避免两次调用“运行”方法并从主方法中只调用一次,或者这是在嵌套阅读器中调用的正确方法?
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
/IO
与 lift
/liftF
组合成 ReaderT
s 并用 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
}