【问题标题】:How to define local method on top of a monad transformer stack in Scala cats如何在 Scala 猫中的 monad 转换器堆栈之上定义本地方法
【发布时间】:2017-01-09 09:40:16
【问题描述】:

我在 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,但是,我找不到如何去做。

我的代码的简单 sn-p 如下:

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] = ???
}

【问题讨论】:

    标签: scala monads monad-transformers scala-cats


    【解决方案1】:

    一个可能的解决方案是手动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))
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-03
      • 1970-01-01
      • 2019-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多