Scala中的读者monad:返回,本地和序列

我正在使用
scalaz库提供的Scala中的Reader monad.我熟悉这个monad
as defined in Haskell.问题是我找不到与return,local和sequence(等等)相当的函数.

目前我使用的是我不喜欢的结构,因为我正在重复自己或使我的代码有点模糊.

关于回归,我目前正在使用:

Reader{_ => someValue}

我宁愿只使用像unit(someValue)这样的构造,但我在互联网上找不到任何东西.像this one这样的教程使用上面的方法,我认为这不是最优的.

关于本地我也必须做类似的事情:而不是输入类似的东西:local f myReader我必须展开它的定义:

Reader{env => myReader.run(f(env))

最后,序列更接近我的期望(作为一个Haskell难民做Scala):

readers: List[Reader[Env, T]]
readerTs: Reader[Env, List[T]] = readers.sequenceU

我对这个实现的问题是,对于Scala而言,它是sequenceU的类型

final class TraverseOps[F[_],A] private[syntax](val self: F[A])(implicit val F: Traverse[F]) extends Ops[F[A]] {
    //...
    def sequenceU(implicit G: Unapply[Applicative, A]): G.M[F[G.A]]

看起来很晦涩,看起来像是黑魔法.理想情况下,我想在Monads上使用序列操作.

scalaz或类似的库上有没有更好的翻译这些构造到Scala?我没有与Scala的任何功能库结合,所以使用其他库的任何解决方案都可以,尽管我更愿意使用scalaz,因为我已经使用它实现了我的代码.

最佳答案 为了使事情更简单,我填写了一些类型.使用泛型类型将它们更改为defs应该仍然有效.

我还提取了ReaderInt类型,以避免与lambda类型混淆.

返回/纯/点

Scala没有自动类型类分辨率,因此您需要隐式提供它们.对于Kleisli(作为读者的monad变换器),
Kleisli [Id,?,?]就足够了

 implicit val KA = scalaz.Kleisli.kleisliIdApplicative[Int]
 type ReaderInt[A] = Kleisli[Id.Id, Int, A]

 val alwaysHello = KA.point("hello")  

或者使用导入的语法:

  import scalaz.syntax.applicative._  
  val alwaysHello = "hello".point[ReaderInt]

所以作为一般规则,你
  1)导入applicative intance,通常位于scalaz.std.something.somethingInstance中
  2)导入scalaz.syntax.something._
  3)然后你可以写x.point [F],其中F是你的应用.

本地
不确定,它回答了你的问题,但Kleisli有一个本地方法.

val f: String ⇒ Int = _.length
val alwaysEleven = alwaysHello local f

测序
同样,您可以自由选择使用语法或明确指定类型类.

  import scalaz.std.list.listInstance
  val initial: List[ReaderInt[String]] = ???  
  val sequenced: ReaderInt[List[String]] = Traverse[List].sequence[ReaderInt, String](initial) 

  import scalaz.syntax.traverse._
  val z = x.sequence[ReaderInt, String]    

我不喜欢使用sequenceU,它使用Unapply typelcass来推断G类型,因为有时scala在找出正确的类型时会遇到麻烦.
而且我个人并不认为自己投入某些类型会很麻烦.

它可能值得研究cats,尽管它还没有多少.

点赞