cats.ReaderT[F,A,B] 来自依赖 A 的理解
cats.ReaderT[F,A,B] from dependency A in for-comprehension
这是一个用例:
import cats.data.ReaderT
trait Service{
type OptionFromMap[A] = ReaderT[Option, Map[String, String], A]
def f1(nameKey:String): OptionFromMap[String] = ReaderT(_.get(nameKey))
def f2(addressKey:String, name:String): OptionFromMap[String] =
ReaderT(map => Option(s"name: $name, address: ${map(addressKey)}"))
}
trait Service2 {
type Env = (Service, Map[String,String])
type OptionFromEnv[A] = ReaderT[Option, Env, A]
import cats.syntax.applicative._
import cats.instances.option._
def f(nameKey:String, addressKey:String): OptionFromEnv[String] =
for {
//wrong try:
s1 <- ReaderT((_:Env) => Option((_:Env)._1))
//wrong try:
s2 <- (_:Env).pure[OptionFromEnv]
name <- s1.f1(nameKey).local((_: Env)._2)
r <- s1.f2(addressKey, name).local((_: Env)._2)
} yield r
}
所以我希望能够调用 Service
的 f1
和 f2
方法。
问题是如何在for-comprehension里面做。通过 ReaderT.apply
,我可以通过以下方式完成它:
def c(nameKey:String, addressKey:String): OptionFromEnv[String] =
ReaderT(env =>
(for {
name <- env._1.f1(nameKey).local((_: Env)._2)
r <- env._1.f2(addressKey, name).local((_: Env)._2)
} yield r)
.run(env)
)
但我试图实现一些东西,看起来像:
import cats.data.Reader
trait Service{
def f1: Reader[Map[String, Int], Int] = Reader(_("name"))
def f2: Reader[Map[String, Int], Int] = Reader(_("age"))
}
trait Service2 {
type Env = (Service, Map[String,Int])
def f(i: Int): Reader[Env, Int] =
for {
s <- Reader((_: Env)._1) //extract input type Service
r1 <- s.f1.local((_: Env)._2)
r2 <- s.f2.local((_: Env)._2)
} yield r1 + r2 + i
}
尝试替换
//wrong try:
s1 <- ReaderT((_:Env) => Option((_:Env)._1))
和
s1 <- ReaderT((env: Env) => Option(env._1))
通过 Kleisli.ask
找到了解决问题的其他方法。不能说哪个选项更好。作为替代方案:
trait Service2 {
def f(nameKey:String, addressKey:String): OptionFromEnv[String] =
for {
env <- Kleisli.ask[Option, Env]
s <- Kleisli.pure(env._1)
name <- env._1.f1(nameKey).local((_: Env)._2)
r <- s.f2(addressKey, name).local((_: Env)._2)
} yield r
}
一般来说,我们有办法获取env
里面的for-comprehension。当然,也没有必要从 env
.
得到 s
这是一个用例:
import cats.data.ReaderT
trait Service{
type OptionFromMap[A] = ReaderT[Option, Map[String, String], A]
def f1(nameKey:String): OptionFromMap[String] = ReaderT(_.get(nameKey))
def f2(addressKey:String, name:String): OptionFromMap[String] =
ReaderT(map => Option(s"name: $name, address: ${map(addressKey)}"))
}
trait Service2 {
type Env = (Service, Map[String,String])
type OptionFromEnv[A] = ReaderT[Option, Env, A]
import cats.syntax.applicative._
import cats.instances.option._
def f(nameKey:String, addressKey:String): OptionFromEnv[String] =
for {
//wrong try:
s1 <- ReaderT((_:Env) => Option((_:Env)._1))
//wrong try:
s2 <- (_:Env).pure[OptionFromEnv]
name <- s1.f1(nameKey).local((_: Env)._2)
r <- s1.f2(addressKey, name).local((_: Env)._2)
} yield r
}
所以我希望能够调用 Service
的 f1
和 f2
方法。
问题是如何在for-comprehension里面做。通过 ReaderT.apply
,我可以通过以下方式完成它:
def c(nameKey:String, addressKey:String): OptionFromEnv[String] =
ReaderT(env =>
(for {
name <- env._1.f1(nameKey).local((_: Env)._2)
r <- env._1.f2(addressKey, name).local((_: Env)._2)
} yield r)
.run(env)
)
但我试图实现一些东西,看起来像:
import cats.data.Reader
trait Service{
def f1: Reader[Map[String, Int], Int] = Reader(_("name"))
def f2: Reader[Map[String, Int], Int] = Reader(_("age"))
}
trait Service2 {
type Env = (Service, Map[String,Int])
def f(i: Int): Reader[Env, Int] =
for {
s <- Reader((_: Env)._1) //extract input type Service
r1 <- s.f1.local((_: Env)._2)
r2 <- s.f2.local((_: Env)._2)
} yield r1 + r2 + i
}
尝试替换
//wrong try:
s1 <- ReaderT((_:Env) => Option((_:Env)._1))
和
s1 <- ReaderT((env: Env) => Option(env._1))
通过 Kleisli.ask
找到了解决问题的其他方法。不能说哪个选项更好。作为替代方案:
trait Service2 {
def f(nameKey:String, addressKey:String): OptionFromEnv[String] =
for {
env <- Kleisli.ask[Option, Env]
s <- Kleisli.pure(env._1)
name <- env._1.f1(nameKey).local((_: Env)._2)
r <- s.f2(addressKey, name).local((_: Env)._2)
} yield r
}
一般来说,我们有办法获取env
里面的for-comprehension。当然,也没有必要从 env
.
s