[英]Why can find `Functor` instance for Tree but not for Branch or Leaf?
I have the following Functor definition: 我有以下Functor定义:
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)
}
}
for: 对于:
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]
Why the compiler complains: 为什么编译器会抱怨:
// <console>:42: error: value map is not a member of wrapper.Branch[
Int]
//
Branch(Leaf(10), Leaf(20)).map(_ * 2)
//
So I have to create a smart constructor: 所以我必须创建一个智能构造函数:
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)
}
What is a smart constructor in this case? 在这种情况下,什么是智能构造函数?
The declaration of Functor[F[_]]
in cats
is invariant in F
. 声明Functor[F[_]]
在cats
是不变的F
。 Therefore, a Functor[Tree]
is neither a generalization, nor a specialization of Functor[Branch]
. 因此, Functor[Tree]
既不是泛化,也不是Functor[Branch]
的专业化。 These types are unrelated. 这些类型是无关的。
The problem with your code is the following. 您的代码存在以下问题。 The expression 表达方式
Branch(Leaf(10), Leaf(20))
is of type Branch[Int]
. 是Branch[Int]
类型。 When you try to apply .map[X]
to it directly, you signal that you would like to get a Branch[X]
as the result. 当您尝试直接将.map[X]
应用于它时,表示您希望获得Branch[X]
作为结果。 But there is no Functor[Branch]
in scope (it's not like you couldn't write one, but as it stands, there is none). 但是范围内没有Functor[Branch]
(它不像你不能写一个,但是就目前而言,没有)。
In order to make use of the Functor[Tree]
, you have to make it clear to the compiler that you want to treat this instance as Tree[Int]
. 为了使用Functor[Tree]
,您必须向编译器明确表示您希望将此实例视为Tree[Int]
。 Casting would work. 铸造会起作用。 Or using a custom factory method that hides Branch
and exposes Tree
would work too: that's what the "smart" constructor is doing. 或者使用隐藏Branch
和暴露Tree
的自定义工厂方法也可以工作:这就是“智能”构造函数正在做的事情。
You can use kittens
and implement instances for Branch
and Leaf
, then the instance for Tree
can be derived. 您可以使用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)
}
Actually then you can derive all three instances: 实际上你可以导出所有三个实例:
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)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.