Scala(?)中类Haskell类型约束特征的实现
在Haskell中,可以构造参数化类型,如下例所示:Scala(?)中类Haskell类型约束特征的实现,scala,haskell,functional-programming,Scala,Haskell,Functional Programming,在Haskell中,可以构造参数化类型,如下例所示: data Tree a = Leaf | Node a (Tree a) (Tree a) ..然后,如果type参数也是同一个typeclass的实例,则将它们作为typeclass的实例(这里使用Eq作为示例,它可以是任何东西): 我想知道类似的事情在Scala中是如何可能的。首先,让我们创建参数化类型: abstract class Tree[T] case class Leaf[T]() extends Tree [T] case
data Tree a = Leaf | Node a (Tree a) (Tree a)
..然后,如果type参数也是同一个typeclass的实例,则将它们作为typeclass的实例(这里使用Eq作为示例,它可以是任何东西):
我想知道类似的事情在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]
…并选择一个更简单的特性作为正在实现的typeclass:
trait Serializable {
def toDifferentString(): String
}
现在,如果T
类型是Serializable
,我希望能够为树
提供一个Serializable
特性的实现
我可以看到一些方法来部分实现,但没有一种方法可以让我得到Haskell那样的结果:
- 添加类型约束
:Scala中的类型类模式如下:
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] }
是上下文绑定,相当于类型为T:Serializable
的隐式参数。Serializable[T]
检索此隐式参数(方法隐式[Serializable[T]
返回类型为隐式[A]
的隐式参数) 对象A
包含生成树序列化程序所需的定义,因此必须导入才能使用。通常,类型类的通用定义放在类型类本身的对象伴侣上,这使得它无需导入即可使用SerializableTree
因为我制作了
contravant,所以Serializable
可以用于Serializable[Tree[T]]
或Serializable[Node[T]]
需要的地方。我正试图最终理顺我的Haskell/Scala知识,因此非常感谢您的帮助。如果我使用的任何术语与我认为的含义不符,请随时纠正我。Serializable[Leaf[T]]
请对此进行扩展?我知道(co)方差的含义,但我看不出它在这里是如何工作的。@nietaki我的错误还请注意,此定义不适用于节点或叶,因为序列化在t中不是协变的。事实上,如果树(及其子类)是协变的,这将是有帮助的。
需要是反向变量,它可以是反向变量,并且不需要Serializable
树的协方差(尽管它在许多情况下仍然有用)。我假设最后一段应该解释逆变在这里扮演的角色,但是,如果不是,我鼓励您比较
的逆变版本和不变版本在传递可序列化
和节点
时的行为。树
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] }