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

nie*_*aki 8 haskell functional-programming scala

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

data Tree a = Leaf | Node a (Tree a) (Tree a)
Run Code Online (Sandbox Code Playgroud)

..然后,如果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
Run Code Online (Sandbox Code Playgroud)

我想知道在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]
Run Code Online (Sandbox Code Playgroud)

..并选择一个更简单的特性作为实现的类型类:

trait Serializable {
  def toDifferentString(): String
}
Run Code Online (Sandbox Code Playgroud)

现在我想要做的是提供Serializable特征的实现Tree,如果T类型是Serializable.

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

  • :<Tree抽象类中添加一个类型约束,但随后它变得不那么通用了,我假设我可以修改Tree
  • 从创建一个隐式转换Tree[Serializable]Serializable,但我也不知道它会工作,这将是多么强劲.

处理这个问题的好方法是什么?

Dan*_*ral 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]
}
Run Code Online (Sandbox Code Playgroud)

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

表示法T : Serializable上下文绑定,相当于类型的隐式参数Serializable[T].通过implicitly[Serializable[T]](该方法implicitly[A]返回类型的隐式参数A)检索此隐式参数.

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

因为我由Serializable逆变中,Serializable[Tree[T]]其中可以使用Serializable[Node[T]]Serializable[Leaf[T]]是必需的.