我有以下函子定义:
import cats.Functor
import cats.syntax.functor._
object Theory {
implicit val treeFunctor: Functor[Tree] =
new Functor[Tree] {
def map[A, B](fa: Tree[A])(f: A => B): Tree[B] =
fa match {
case Branch(left, right) =>
Branch(map(left)(f), map(right)(f))
case Leaf(value) =>
Leaf(f(value))
}
}
def main(args: Array[String]): Unit = {
Branch(Leaf(10), Leaf(20)).map(_ * 2)
}
}
为:
sealed trait Tree[+A]
final case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]
final case class Leaf[A](value: A) extends Tree[A]
编译器抱怨的原因:
// <console>:42: error: value map is not a member of wrapper.Branch[
Int]
//
Branch(Leaf(10), Leaf(20)).map(_ * 2)
//
所以我必须创建一个智能构造函数:
object Tree {
def branch[A](left: Tree[A], right: Tree[A]): Tree[A] =
Branch(left, right)
def leaf[A](value: A): Tree[A] =
Leaf(value)
}
在这种情况下,什么是智能构造函数?
cats
中 Functor[F[_]]
的声明在 F
中是不变的。因此,Functor[Tree]
既不是概括,也不是Functor[Branch]
的专业化。这些类型是不相关的。
代码的问题如下。表达式
Branch(Leaf(10), Leaf(20))
属于 Branch[Int]
型。当您尝试直接对其应用.map[X]
时,您表示您希望获得结果Branch[X]
。但是范围没有Functor[Branch]
(并不是说你不能写一个,但就目前而言,没有(。
为了利用Functor[Tree]
,您必须向编译器明确表示要将此实例视为Tree[Int]
。选角会起作用。或者使用隐藏Branch
并公开Tree
的自定义工厂方法也可以:这就是"智能"构造函数正在做的事情。
kittens
来实现Branch
和Leaf
的实例,然后可以派生Tree
的实例。
libraryDependencies += "org.typelevel" %% "kittens" % "1.0.0-RC2"
import cats.Functor
import cats.syntax.functor._
sealed trait Tree[+A]
final case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]
final case class Leaf[A](value: A) extends Tree[A]
implicit val treeFunctor: Functor[Tree] = cats.derive.functor[Tree]
implicit val branchFunctor: Functor[Branch] =
new Functor[Branch] {
def map[A, B](fa: Branch[A])(f: A => B): Branch[B] =
fa match {
case Branch(left, right) =>
Branch(left.map(f), right.map(f))
}
}
// or without extension method
// implicit def branchFunctor(implicit treeFunctor: Functor[Tree]): Functor[Branch] =
// new Functor[Branch] {
// def map[A, B](fa: Branch[A])(f: A => B): Branch[B] =
// fa match {
// case Branch(left, right) =>
// Branch(treeFunctor.map(left)(f), treeFunctor.map(right)(f))
// }
// }
implicit val leafFunctor: Functor[Leaf] =
new Functor[Leaf] {
def map[A, B](fa: Leaf[A])(f: A => B): Leaf[B] =
fa match {
case Leaf(value) =>
Leaf(f(value))
}
}
def main(args: Array[String]): Unit = {
(Branch(Leaf(10), Leaf(20)): Tree[Int]).map(_ * 2)
Branch(Leaf(10), Leaf(20)).map(_ * 2)
Leaf(10).map(_ * 2)
}
实际上,您可以推导出所有三个实例:
implicit val treeFunctor: Functor[Tree] = cats.derive.functor[Tree]
implicit val leafFunctor: Functor[Leaf] = cats.derive.functor[Leaf]
implicit val branchFunctor: Functor[Branch] = cats.derive.functor[Branch]
def main(args: Array[String]): Unit = {
(Branch(Leaf(10), Leaf(20)): Tree[Int]).map(_ * 2)
Branch(Leaf(10), Leaf(20)).map(_ * 2)
Leaf(10).map(_ * 2)
}