gpt4 book ai didi

scala - Scalaz 的 Reader Monad

转载 作者:行者123 更新时间:2023-12-04 05:34:50 26 4
gpt4 key购买 nike

我尝试用 scalaz 定义 Reader monad,如下所示:

import scalaz._
import Scalaz._

final class Reader[E,A](private[Reader] val runReader: E => A)

object Reader {
def apply[E,A](f: E => A) = new Reader[E,A](f)
def env[E]: Reader[E,E] = Reader(identity _)

implicit def ReaderMonad[E] = new Monad[PartialApply1Of2[Reader,E]#Apply] {
def pure[A](a: => A) = Reader(_ => a)

def bind[A,B](m: Reader[E,A], k: A => Reader[E,B]) =
Reader(e => k(m.runReader(e)).runReader(e))
}
}


object Test {
import Reader._

class Env(val s: String)

def post(s: String): Reader[Env, Option[String]] =
env >>= (e => if (e.s == s) some(s).pure else none.pure)
}

但我得到一个编译器错误:
reader.scala:27: reassignment to val
env >>= (e => if (e.s == s) some(s).pure else none.pure)
^

这是为什么?

谢谢,
列维

最佳答案

即使按照 Scala 的标准,这个错误也是相当不透明的。以 = 结尾的方法名称被特殊对待——它们首先被视为普通标识符,否则,它们将被扩展为自赋值。

scala> def env[A] = 0
env: [A]Int

scala> env >>= 0
<console>:7: error: reassignment to val
env >>= 0
^

scala> env = env >> 0
<console>:6: error: reassignment to val
env = env >> 0
^

如果您对程序的语法解释感到困惑,最好运行 scalac -Xprint:parser看看发生了什么。同样,您可以使用 -Xprint:typer-Xprint:jvm查看程序转换的后期阶段。

那么,如何调用 >>=在您的 Reader 上?首先,您需要显式传递类型参数 Envenv .结果 Reader[Env, Env]然后必须转换为 MA[M[_], A] .对于简单类型构造函数,隐式转换 MAs#ma就足够了。然而两个参数类型的构造函数 Reader必须部分应用——这意味着它不能被推断出来,而是你必须提供一个特定的隐式转换。

如果 Adriaan 找到一个空闲的下午到 implement higher-order unification for type constructor inference,情况将会大大改善。 . :)

在那之前,这是你的代码。还有一些评论是内联的。
import scalaz._
import Scalaz._

final class Reader[E, A](private[Reader] val runReader: E => A)

object Reader {
def apply[E, A](f: E => A) = new Reader[E, A](f)

def env[E]: Reader[E, E] = Reader(identity _)

implicit def ReaderMonad[E]: Monad[PartialApply1Of2[Reader, E]#Apply] = new Monad[PartialApply1Of2[Reader, E]#Apply] {
def pure[A](a: => A) = Reader(_ => a)

def bind[A, B](m: Reader[E, A], k: A => Reader[E, B]) =
Reader(e => k(m.runReader(e)).runReader(e))
}

// No Higher Order Unification in Scala, so we need partially applied type constructors cannot be inferred.
// That's the main reason for defining function in Scalaz on MA, we can create one implicit conversion
// to extract the partially applied type constructor in the type parameter `M` of `MA[M[_], A]`.
//
// I'm in the habit of explicitly annotating the return types of implicit defs, it's not strictly necessary
// but there are a few corner cases it pays to avoid.
implicit def ReaderMA[E, A](r: Reader[E, A]): MA[PartialApply1Of2[Reader, E]#Apply, A] = ma[PartialApply1Of2[Reader, E]#Apply, A](r)
}


object Test {
import Reader._

class Env(val s: String)

def post(s: String): Reader[Env, Option[String]] =
// Need to pass the type arg `Env` explicitly here.
env[Env] >>= {e =>
// Intermediate value and type annotation not needed, just here for clarity.
val o: Option[String] = (e.s === s).guard[Option](s)
// Again, the partially applied type constructor can't be inferred, so we have to explicitly pass it.
o.pure[PartialApply1Of2[Reader, Env]#Apply]
}
}

关于scala - Scalaz 的 Reader Monad,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3284483/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com