我想更新以前的答案,但是由于您创建了单独的问题,所以我把它放在这里。
scalaz.syntax
让我们考虑这个point
例子,你可以对其他方法应用相同的推理。
point
(或haskell's return
)或pure
(只是一个类型别名)属于Applicative
特征。如果你想在一些里面放一些东西F
,你至少需要Applicative
这个实例F
。
通常,您将通过导入隐式提供它,但您也可以显式指定它。
在第一个问题的示例中,我将其分配给val
implicit val KA = scalaz.Kleisli.kleisliIdApplicative[Int]
因为 scala 无法找出Int
这个应用程序的相应类型。换句话说,它不知道要为哪个 Reader引入 Applicative。(尽管有时编译器可以弄清楚)
对于只有一个类型参数的 Applicatives,我们可以通过 import 引入隐式实例
import scalaz.std.option.optionInstance
import scalaz.std.list.listInstance
ETC...
好的,你有实例。现在你需要调用point
它。你有几个选择:
1.直接访问方法:
scalaz.std.option.optionInstance.point("hello")
KA.pure("hello")
2.从隐式上下文中显式拉取它:
Applicative[Option].point("hello")
如果您查看 Applicative 对象,您会看到
object Applicative {
@inline def apply[F[_]](implicit F: Applicative[F]): Applicative[F] = F
}
的实现apply
只是返回Applicative[F]
某种类型的对应实例F
。
所以Applicative[Option].point("hello")
转换为
Applicative[Option].apply(scalaz.std.option.optionInstance)
到底是哪个optionInstance
3.使用语法
import scalaz.syntax.applicative._
将此方法带入隐式范围:
implicit def ApplicativeIdV[A](v: => A) = new ApplicativeIdV[A] {
val nv = Need(v)
def self = nv.value
}
trait ApplicativeIdV[A] extends Ops[A] {
def point[F[_] : Applicative]: F[A] = Applicative[F].point(self)
def pure[F[_] : Applicative]: F[A] = Applicative[F].point(self)
def η[F[_] : Applicative]: F[A] = Applicative[F].point(self)
} ////
因此,每当您尝试point
调用String
"hello".point[Option]
编译器意识到,String
没有方法point
并开始查看implicits,它如何能得到有的东西point
,从String
。
它发现,它可以转换String
为ApplicativeIdV[String]
,它确实有方法point
:
def point[F[_] : Applicative]: F[A] = Applicative[F].point(self)
所以最后 - 你的电话取消了
new ApplicativeIdV[Option]("hello")
scalaz 中的所有类型类或多或少都以相同的方式工作。对于sequence
,实现是
def sequence[G[_]: Applicative, A](fga: F[G[A]]): G[F[A]] =
traverse(fga)(ga => ga)
这个冒号之后G
的意思是,Applicative[G]
应该隐式提供。它本质上与以下内容相同:
def sequence[G[_], A](fga: F[G[A]])(implicit ev: Applicative[G[_]]): G[F[A]] =
traverse(fga)(ga => ga)
所以你只需要 Applicative[G] 和 Traverse[F]。
import scalaz.std.list.listInstance
import scalaz.std.option.optionInstance
Traverse[List].sequence[Option, String](Option("hello"))