Scala中类似Haskell的类型约束特征实现(?)

时间:2013-09-09 09:25:41

标签: scala haskell functional-programming

在Haskell中,您可以构建参数化类型,如以下示例所示:

data Tree a = Leaf | Node a (Tree a) (Tree a)

..然后使它们成为类型类的实例,如果type参数也是同一类型类的实例(这里使用Eq作为示例,它可以是任何东西):

instance (Eq m) => Eq (Tree m) where
  Leaf == Leaf = True
  Node a b c == Node x y z = (a == x) && (b == y) && (c == z)
  _ == _ = False

我想知道Scala中可能会出现类似的事情。要开始,让我们创建参数化类型:

abstract class Tree[T]
case class Leaf[T]() extends Tree [T]
case class Node[T](value: T, left: Tree[T], right: Tree[T]) extends Tree [T]

..并且在实现类型类时选择一个更简单的特性:

trait Serializable {
  def toDifferentString(): String
}

如果Serializable类型为Tree,我现在希望能够为T提供Serializable特征的实现。

我可以看到几种如何部分地完成它的方法,但没有一种能让我得到类似Haskell的结果:

  • :<抽象类中添加类型约束Tree,但随后它变得不那么通用了,我假设我可以修改Tree
  • 创建从Tree[Serializable]Serializable的隐式转换,但我甚至不确定它是否会起作用以及它会有多强大。

解决问题的好方法是什么?

1 个答案:

答案 0 :(得分:12)

Scala中的类型类模式如下:

trait Serializable[-T] {
  def toDifferentString(v: T): String
}

class SerializableTree[T : Serializable] extends Serializable[Tree[T]] {
  def toDifferentString(t: Tree[T]) = t match {
    case Leaf() => ""
    case Node(v, left, right) => 
      val vStr = implicitly[Serializable[T]].toDifferentString(v)
      val lStr = toDifferentString(left)
      val rStr = toDifferentString(right)
      s"Node($vStr, $lStr, $rStr)"
  }
}

object SerializableTree {
  implicit def st[T : Serializable]: Serializable[Tree[T]] = new SerializableTree[T]
}

Scala中的类型类是作为模式实现的,其中类型类提供了一个或多个方法,这些方法将其提供这些方法的类作为其参数之一。

表示法T : Serializable上下文绑定,等同于Serializable[T]类型的隐式参数implicitly[Serializable[T]]正在检索此隐式参数(方法implicitly[A]返回类型为A的隐式参数)。

对象SerializableTree包含为树生成序列化程序所必需的定义,因此必须导入才能使用它。通常,类型类的常见定义放在类型类本身的对象伴随上,这使得它在没有导入的情况下可用。

由于我提出Serializable逆变,因此Serializable[Tree[T]]可用于需要Serializable[Node[T]]Serializable[Leaf[T]]的地方。