Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala(?)中类Haskell类型约束特征的实现_Scala_Haskell_Functional Programming - Fatal编程技术网

Scala(?)中类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

在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 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中的类型类模式如下:

    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]
    的隐式参数。
    隐式[Serializable[T]
    检索此隐式参数(方法
    隐式[A]
    返回类型为
    A
    的隐式参数)

    对象
    SerializableTree
    包含生成树序列化程序所需的定义,因此必须导入才能使用。通常,类型类的通用定义放在类型类本身的对象伴侣上,这使得它无需导入即可使用


    因为我制作了
    Serializable
    contravant,所以
    Serializable[Tree[T]]
    可以用于
    Serializable[Node[T]]
    Serializable[Leaf[T]]
    需要的地方。

    我正试图最终理顺我的Haskell/Scala知识,因此非常感谢您的帮助。如果我使用的任何术语与我认为的含义不符,请随时纠正我。
    还请注意,此定义不适用于节点或叶,因为序列化在t中不是协变的。事实上,如果树(及其子类)是协变的,这将是有帮助的。
    请对此进行扩展?我知道(co)方差的含义,但我看不出它在这里是如何工作的。@nietaki我的错误
    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]
    }