value map不是Branch [Int]的成员

时间:2017-05-03 06:58:34

标签: scala

我跟随ADT:

import cats.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 def treeFunctor = 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(v) => Leaf(f(v))
    }
}

并按如下方式使用:

val b = Branch(left = Branch(Branch(Leaf(5), Leaf(3)), Leaf(10)), Leaf(45))
val functorTree = Functor[Tree].map(b)((v) => v * 4)

但是:

Branch(Leaf(10), Leaf(20)).map(_ * 2)

我收到了编译错误:

Error:(21, 29) value map is not a member of A$A90.this.Branch[Int]
Branch(Leaf(10), Leaf(20)).map(_ * 2)
                           ^

我的问题是为什么我会收到错误?

2 个答案:

答案 0 :(得分:3)

方法treeFunctor为您提供Functor[Tree]的{​​{1}}实例,但这并不意味着任何Tree会自动转换为Tree。只是对于任何Tree,您在范围内都有Functor[Tree]的隐式实例。

这个隐式实例有一个方法map,它有两个参数:映射的Functor[Tree]实例,以及映射函数本身。

所以这应该有效:

implicitly[Functor[Tree]].map(Branch(Leaf(10), Leaf(20)))(_ * 2)

或只是

Functor[Tree].map(Branch(Leaf(10), Leaf(20)))(_ * 2)

(因为scalaz和猫通常有类型类的方便apply())

编辑:在阅读您的问题时,我错过了Functor[Tree].map(b)((v) => v * 4)部分。所以你真正感兴趣的是以下部分。

如果要保留调用map的语法,可以创建一个隐式类作为包装器:

implicit class toTreeFunctor[A](tree: Tree[A]) {
  def map[B](f: A => B) = Functor[Tree].map(tree)(f)
}

Branch(Leaf(10), Leaf(20)).map(_ * 2)

正如@P指出的那样。 Frolov,您可以从import scalaz.syntax.functor._import cats.syntax.functor._免费获得此隐式转化,但请注意,您必须明确地将Branch转发为Tree的实例。

答案 1 :(得分:2)

由于您正在使用Cats,因此您可以import cats.syntax.functor._获取map。请注意,您需要将分支转换为基本类型,因为Functor实例是为Tree定义的,而不仅仅是单独的Branch。您可以在随播对象中使用类型注释或智能构造函数来执行此操作。

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 def treeFunctor = 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(v) => Leaf(f(v))
    }
}

val tree: Tree[Int] = Branch(Leaf(10), Leaf(20))
tree.map(_ * 2) // Branch(Leaf(20), Leaf(40))

cats.syntax.functor实际上只是一个扩展FunctorSyntax特征的单例对象,包含从实现Functor的类到包装器的隐式转换,就像在slouc的答案中一样。包装器本身Functor.Ops由Simulacrum @typeclass宏生成。