4

Reader在 Scala 中使用由scalaz库提供的 monad。我熟悉Haskell 中定义的这个 monad 。问题是我找不到等效于returnlocalsequence(以及其他)的函数。

目前我使用我不喜欢的构造,因为我在重复自己或使我的代码有点晦涩。

关于return,我目前正在使用:

Reader{_ => someValue}

我宁愿只使用类似的构造unit(someValue),但我在互联网上找不到任何东西。有像这样的教程使用上述方法,我认为这不是最佳的。

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

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

最后,序列有点接近我的预期(作为一个使用 Scala 的 Haskell 难民):

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]]

看起来相当晦涩,似乎是黑魔法。理想情况下,我想sequence在 Monads 上使用操作。

scalaz 或类似库上是否有将这些构造更好地转换为 Scala 的方法?我没有与 Scala 的任何函数库结婚,因此任何使用其他库的解决方案都可以,尽管我宁愿使用 scalaz 来回答,因为我已经使用它实现了我的代码。

4

1 回答 1

1

为了使事情更简单,我填写了一些类型。将它们更改为具有泛型类型的 def 仍然可以工作。我还提取了ReaderInt类型,以避免与类型 lambda 混淆。

返回/纯/点

Scala 没有自动类型类解析,因此您需要隐式提供它们。对于Kleisli(作为读者的单子变压器), 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)导入应用实例,通常位于scalaz.std.something.somethingInstance

2)import scalaz.syntax.something._

3)然后你可以写x.point[F]F你的应用程序在哪里。

当地的

不确定,它回答了你的问题,但Kleisli有一个local方法。

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

测序

同样,您可以自由选择使用syntaxfor 或明确指定类型类。

  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,它使用Unapplytypelcass 来推断G类型,因为有时 scala 很难找出正确的类型。而且我个人认为自己放入某些类型并不麻烦。

可能值得研究一下,尽管它还没有太多。

于 2016-07-24T15:36:15.523 回答