读者 Monad 与 Scalaz
我尝试使用 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)
^
这是为什么?
谢谢, 列维
I try to define the Reader monad with scalaz like this:
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)
}
but I get a compiler error:
reader.scala:27: reassignment to val
env >>= (e => if (e.s == s) some(s).pure else none.pure)
^
Why is that?
Thanks,
Levi
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
即使按照 Scala 的标准,这个错误也是相当不透明的。以
=
结尾的方法名称会被特殊对待——它们首先被视为普通标识符,如果失败,它们将扩展为自赋值。如果您对程序的语法解释感到困惑,最好运行 scalac -Xprint:parser 来查看发生了什么。同样,您可以使用
-Xprint:typer
或-Xprint:jvm
查看程序转换的后续阶段。那么,如何在
Reader
上调用>>=
呢?首先,您需要将类型参数Env
显式传递给env
。然后,必须将生成的 Reader[Env, Env] 转换为MA[M[_], A]
。对于简单类型构造函数,隐式转换MAs#ma
就足够了。但是,两个参数类型构造函数Reader
必须部分应用 - 这意味着它无法推断,而您必须提供特定的隐式转换。如果 Adriaan 找到一个空闲的下午实现类型的高阶统一,情况将会大大改善构造函数推断。 :)
在那之前,这是您的代码。还有一些内联评论。
This error is fairly opaque, even by Scala's standards. Method names ending with
=
are treated specially -- they are first considered as a normal identifier, and failing that, they are expanded to a self assignment.If you're confused about the syntactic interpretation of your program, it's a good idea to run
scalac -Xprint:parser
to see what's going on. Similarly, you can use-Xprint:typer
or-Xprint:jvm
to see later phases of the program transformation.So, how do you call
>>=
on yourReader
? First of all, you'll need to explicitly pass the type argumentEnv
toenv
. The resultingReader[Env, Env]
must then be converted to aMA[M[_], A]
. For simple type constructors, the implicit conversionMAs#ma
will suffice. However the two param type constructorReader
must be partially applied -- this means it can't be inferred and instead you must provide a specific implicit conversion.The situation would be vastly improved if Adriaan ever finds a spare afternoon to implement higher-order unification for type constructor inference. :)
Until then, here's your code. A few more comments are inline.