在Scala中Typesafe完美的二叉树

时间:2015-10-20 18:28:04

标签: scala types

我正在尝试在Scala中实现typesafe perfect binary tree。换句话说,应该编译以下内容:

 Succ(Node(Leaf("a"), Leaf("b")))
 Node(
   Succ(Node(Leaf("a"), Leaf("b"))),
   Succ(Node(Leaf("c"), Leaf("d"))))

但以下不应该:

 Node(
   Succ(Node(Leaf("a"), Leaf("b"))),
   Leaf("c"))

我提出了满足上述要求的解决方案,但是可以欺骗编译器:

Node(
   Leaf("f"): PerfectBinaryTree,
   Succ(Node(Leaf("a"), Leaf("b"))): PerfectBinaryTree)

Scala有没有办法避免这种情况? 它与Haskell有什么不同(如果有的话)?

trait PerfectBinaryTree {
    type N <: PerfectBinaryTree
  }

  case class Succ[P <: PerfectBinaryTree](p: P) extends PerfectBinaryTree {
    type N = Succ[P]
  }

  class Leaf[T] private (t: T) extends PerfectBinaryTree {
    type N = Leaf[T]
  }

  object Leaf {
    def apply[T](t: T): Leaf[T] = new Leaf(t)
  }

  case class Node[A <: PerfectBinaryTree, B <: PerfectBinaryTree](l: A, r: B)(implicit evidence: A =:= B) extends PerfectBinaryTree {
    type N = A
  }

1 个答案:

答案 0 :(得分:4)

技巧(就像在Haskell中一样)是在类型变量(polymorphic recursion)内传递Node

然后,类的定义变得非常简单

case class Node[+A](left: A, right: A);

sealed trait Tree[+A];
case class Succ[+A](subtree: Tree[Node[A]]) extends Tree[A];
case class Leaf[+A](value: A) extends Tree[A];

(当然你想要添加折叠/遍历这样的树等功能。)

然后,在创建值时,Succ构造函数的数量决定了叶子需要多少Node个。请注意,始终只有一个叶子,但它包含一个由给定数量的Node级别组成的二叉树:

val sample: Tree[String] =
 Succ(
  Succ(
    Leaf(
      Node(
        Node("a", "b"),
        Node("c", "d")
      )
    )
  )
);