下面是一个用例:
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- question中实现它。通过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
}发布于 2019-07-19 16:45:24
尝试替换
//wrong try:
s1 <- ReaderT((_:Env) => Option((_:Env)._1))使用
s1 <- ReaderT((env: Env) => Option(env._1))发布于 2019-10-17 15:47:40
找到了通过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- general内部。当然,也没有必要从env获取s。
https://stackoverflow.com/questions/57107370
复制相似问题