如何在 Scala cat 中的 monad 转换器堆栈之上定义本地方法
How to define local method on top of a monad transformer stack in Scala cats
我在 Kleisli 之上有一个 monad 转换器堆栈,定义为:
type Env = Map[String,Int]
type MyState = List[Int]
type S[A] = EitherT[StateT[WriterT[Kleisli[List,Env,?],String,?],MyState,?], String, A]
并且我想定义一个具有以下签名的 local
方法:
def localE[A](f: Env => Env)(sa: S[A]): S[A] = ???
可能吗?
我知道 MonadReader
中有一个 local
方法,签名为:
def local[A](f: R => R)(fa: F[A]): F[A]
所以最简单的解决方案是从 S
获取隐含的 MonadReader
,但是,我找不到如何去做。
我的代码的一个简单片段如下:
package examples
import cats._, data._
import cats.implicits._
object local {
type Env = Map[String,Int]
type MyState = List[Int]
type S[A] = EitherT[StateT[WriterT[Kleisli[List,Env,?],String,?],MyState,?], String, A]
// The following definition doesn't compile
// implicit lazy val mr = MonadReader[S,Env]
// Modify the environment
def localE[A](f: Env => Env)(sa: S[A]): S[A] = ???
}
一个可能的解决方案是 unlift
手动堆叠 monad。在本例中,我定义了以下两个辅助函数:
def localW[A](f: Env => Env)
(c: WriterT[Kleisli[List,Env,?],String,A]):
WriterT[Kleisli[List,Env,?],String,A] = {
type WriterTF[F[_],A] = WriterT[F, String, A]
val r: WriterT[Kleisli[List,Env,?],String,(String,A)] =
c.run.local(f).liftT[WriterTF]
r.mapBoth { case (_, (w, x)) => (w, x) }
}
def localS[A](f: Env => Env)
(c: StateT[WriterT[Kleisli[List,Env,?],String,?],MyState,A]):
StateT[WriterT[Kleisli[List,Env,?],String,?],MyState,A] = {
StateT(s => localW(f)(c.run(s)))
}
而局部函数可以定义为:
def localE[A](f: Env => Env)(sa: S[A]): S[A] = {
EitherT(localS(f)(sa.value))
}
我在 Kleisli 之上有一个 monad 转换器堆栈,定义为:
type Env = Map[String,Int]
type MyState = List[Int]
type S[A] = EitherT[StateT[WriterT[Kleisli[List,Env,?],String,?],MyState,?], String, A]
并且我想定义一个具有以下签名的 local
方法:
def localE[A](f: Env => Env)(sa: S[A]): S[A] = ???
可能吗?
我知道 MonadReader
中有一个 local
方法,签名为:
def local[A](f: R => R)(fa: F[A]): F[A]
所以最简单的解决方案是从 S
获取隐含的 MonadReader
,但是,我找不到如何去做。
我的代码的一个简单片段如下:
package examples
import cats._, data._
import cats.implicits._
object local {
type Env = Map[String,Int]
type MyState = List[Int]
type S[A] = EitherT[StateT[WriterT[Kleisli[List,Env,?],String,?],MyState,?], String, A]
// The following definition doesn't compile
// implicit lazy val mr = MonadReader[S,Env]
// Modify the environment
def localE[A](f: Env => Env)(sa: S[A]): S[A] = ???
}
一个可能的解决方案是 unlift
手动堆叠 monad。在本例中,我定义了以下两个辅助函数:
def localW[A](f: Env => Env)
(c: WriterT[Kleisli[List,Env,?],String,A]):
WriterT[Kleisli[List,Env,?],String,A] = {
type WriterTF[F[_],A] = WriterT[F, String, A]
val r: WriterT[Kleisli[List,Env,?],String,(String,A)] =
c.run.local(f).liftT[WriterTF]
r.mapBoth { case (_, (w, x)) => (w, x) }
}
def localS[A](f: Env => Env)
(c: StateT[WriterT[Kleisli[List,Env,?],String,?],MyState,A]):
StateT[WriterT[Kleisli[List,Env,?],String,?],MyState,A] = {
StateT(s => localW(f)(c.run(s)))
}
而局部函数可以定义为:
def localE[A](f: Env => Env)(sa: S[A]): S[A] = {
EitherT(localS(f)(sa.value))
}