这个问题与
this one有关,我试图了解如何在Scala中使用阅读器monad.
在答案中,autor使用以下代码获取ReaderInt [String]的实例:
import scalaz.Syntax.applicative._ val alwaysHello2: ReaderInt[String] = "hello".point[ReaderInt]
Scala使用哪种机制来解析表达式“hello”.point [ReaderInt]的类型,以便它使用正确的点函数?
解决方法
每当你试图弄清楚这样的事情时,一个好的第一步是使用反射API去除表达式:
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,但对于像这样的调查来说它非常方便.)
当编译器看到你试图在没有point方法的类型上调用.point [ReaderInt]时 – 在这种情况下String-it开始查找将String转换为具有匹配点的类型的隐式转换方法(在Scala中称为“浓缩”).我们可以从showCode的输出中看到,它找到的隐式转换是在applicative语法对象中称为applicativeIdV的方法.
然后,它将此转换应用于String,从而生成applicativeIdV [String]类型的值.这种类型的point方法如下所示:
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,并开始寻找实例.
它看起来的第一个地方之一将是Kleisli伴侣对象,因为它想要一个包含Kleisli的类型的隐式值,实际上showCode告诉我们它找到的那个是Kleisli.kleisliIdMonadReader.那时它就完成了,我们得到了我们想要的ReaderInt [String].