Scalaz:`scalaz.syntax.applicative._` 如何发挥它的魔力 [英] Scalaz: how does `scalaz.syntax.applicative._` works its magic
问题描述
这个问题与这个问题有关,其中我试图了解如何在 Scala 中使用 reader monad.
This question is related to this one, where I was trying to understand how to use the reader monad in Scala.
在答案中,作者使用以下代码获取 ReaderInt[String]
的实例:
In the answer the autor uses the following code for getting an instance of ReaderInt[String]
:
import scalaz.syntax.applicative._
val alwaysHello2: ReaderInt[String] = "hello".point[ReaderInt]
Scala 使用哪种机制来解析表达式 "hello".point[ReaderInt]
的类型,以便它使用正确的 point
函数?
Which mechanisms does Scala use to resolve the type of the expression "hello".point[ReaderInt]
so that it uses the right point
function?
推荐答案
每当您试图找出类似问题时,最好的第一步就是使用反射 API 来对表达式进行脱糖:
A good first step any time you're trying to figure out something like this is to use the reflection API to desugar the expression:
scala> import scalaz.Reader, scalaz.syntax.applicative._
import scalaz.Reader
import scalaz.syntax.applicative._
scala> import scala.reflect.runtime.universe.{ reify, showCode }
import scala.reflect.runtime.universe.{reify, showCode}
scala> type ReaderInt[A] = Reader[Int, A]
defined type alias ReaderInt
scala> showCode(reify("hello".point[ReaderInt]).tree)
res0: String = `package`.applicative.ApplicativeIdV("hello").point[$read.ReaderInt](Kleisli.kleisliIdMonadReader)
(您通常不希望在实际代码中使用 scala.reflect.runtime
,但它对于此类调查非常方便.)
(You generally don't want to use scala.reflect.runtime
in real code, but it's extremely handy for investigations like this.)
当编译器发现您试图在没有 point
方法的类型上调用 .point[ReaderInt]
时——在本例中为 String
——它开始寻找将 String
转换为具有匹配 point
方法的类型的隐式转换(这在 Scala 中称为浓缩").我们从showCode
的输出中可以看出,它找到的隐式转换是applicative
语法对象中名为ApplicativeIdV
的方法.
When the compiler sees you trying to call .point[ReaderInt]
on a type that doesn't have a point
method—in this case String
—it starts looking for implicit conversions that would convert a String
into a type that does have a matching point
method (this is called "enrichment" in Scala). We can see from the output of showCode
that the implicit conversion it finds is a method called ApplicativeIdV
in the applicative
syntax object.
然后将这个转换应用到 String
,产生 ApplicativeIdV[String]
类型的值.该类型的 point
方法如下所示:
It then applies this conversion to the String
, resulting in a value of type ApplicativeIdV[String]
. This type's point
method looks like this:
def point[F[_] : Applicative]: F[A] = Applicative[F].point(self)
以下内容的语法糖:
def point[F[_]](implicit F: Applicative[F]): F[A] = F.point(self)
所以接下来需要做的是为 F
找到一个 Applicative
实例.在您的情况下,您已明确指定 F
是 ReaderInt
.它将别名解析为 Reader[Int, _]
,它本身就是 Kleisli[Id.Id, Int, _]
的别名,并开始寻找实例.
So the next thing it needs to do is find an Applicative
instance for F
. In your case you've explicitly specified that F
is ReaderInt
. It resolves the alias to Reader[Int, _]
, which is itself an alias for Kleisli[Id.Id, Int, _]
, and starts looking for an instance.
它首先看到的地方之一将是 Kleisli
伴随对象,因为它需要一个包含 Kleisli
的类型的隐式值,实际上是 showCode
告诉我们它找到的是 Kleisli.kleisliIdMonadReader
.到那时它就完成了,我们得到了我们想要的 ReaderInt[String]
.
One of the first places it looks will be the Kleisli
companion object, since it wants an implicit value of a type that includes Kleisli
, and in fact showCode
tells us that the one it finds is Kleisli.kleisliIdMonadReader
. At that point it's done, and we get the ReaderInt[String]
we wanted.
这篇关于Scalaz:`scalaz.syntax.applicative._` 如何发挥它的魔力的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!