【问题标题】:Why can find `Functor` instance for Tree but not for Branch or Leaf?为什么可以找到 Tree 的 Functor 实例,但找不到 Branch 或 Leaf?
【发布时间】:2018-01-31 14:52:07
【问题描述】:

我有以下 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)
  }


}

为:

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)
}

在这种情况下,什么是智能构造函数?

【问题讨论】:

  • 将定义的函子用于Tree 而不是Branch

标签: scala scala-cats invariance


【解决方案1】:

Functor[F[_]]cats 中的声明在F 中是不变的。 因此,Functor[Tree] 既不是泛化,也不是Functor[Branch] 的特化。这些类型是不相关的。

您的代码存在以下问题。表达式

Branch(Leaf(10), Leaf(20))

类型为Branch[Int]。当您尝试直接对其应用.map[X] 时,您表示您希望得到Branch[X] 作为结果。但是范围内没有Functor[Branch](并不是说你不会写,但就目前而言,没有)。

为了使用Functor[Tree],您必须向编译器明确说明您希望将此实例视为Tree[Int]。铸造会起作用。或者使用隐藏 Branch 并暴露 Tree 的自定义工厂方法也可以:这就是“智能”构造函数正在做的事情。

【讨论】:

  • 我要补充一点,Functor[F[_]]F 中是不变的,而不仅仅是在cats 中,它在F 中也是不变的。 stackoverflow.com/questions/47181109/…
  • @DmytroMitin 嗯... 思考:需要F[A], A =&gt; B,返回F[B]...需要F,返回F... /thinking 哦,是的,确实!你是绝对正确的!我认为有一些关于是否可以使F[+_] 成为协变的讨论,但事实并非如此。所以,是的,评论接受了。谢谢!
【解决方案2】:

您可以使用kittens,实现BranchLeaf的实例,然后可以派生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)
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-22
    • 2014-09-01
    相关资源
    最近更新 更多