scala - Scala协方差-现实生活中的例子

标签 scala computer-science

我了解scala中的协方差和自变量。协方差在现实世界中有很多应用程序,但是对于函数协方差应用程序,除了函数的相同旧示例,我想不出任何东西。

有人可以阐明的真实世界示例的用法吗?

最佳答案

我认为,Function之后的两个最简单的示例是排序和相等。但是,第一个在Scala的标准库中不是反变量,而第二个甚至不存在于其中。因此,我将使用Scalaz等效项:OrderEqual

接下来,我需要一些类层次结构,最好是一个熟悉的类层次结构,当然,以上两个概念都必须对此有意义。如果Scala具有所有数字类型的Number父类(super class),那将是完美的。不幸的是,它没有这样的东西。

因此,我将尝试使用集合制作示例。为了简单起见,我们只考虑Seq[Int]List[Int]。应该清楚List[Int]Seq[Int]的子类型,即List[Int] <: Seq[Int]

那么,我们该怎么办呢?首先,让我们写一些比较两个列表的内容:

def smaller(a: List[Int], b: List[Int])(implicit ord: Order[List[Int]]) =
  if (ord.order(a,b) == LT) a else b

现在,我将为Order编写一个隐式Seq[Int]:
implicit val seqOrder = new Order[Seq[Int]] { 
  def order(a: Seq[Int], b: Seq[Int]) = 
    if (a.size < b.size) LT
    else if (b.size < a.size) GT
    else EQ
}

有了这些定义,我现在可以执行以下操作:
scala> smaller(List(1), List(1, 2, 3))
res0: List[Int] = List(1)

请注意,我要的是Order[List[Int]],但我要传递的是Order[Seq[Int]]。这意味着Order[Seq[Int]] <: Order[List[Int]]。给定Seq[Int] >: List[Int],这仅可能由于反差。

下一个问题是:这有意义吗?

让我们再次考虑smaller。我想比较两个整数列表。自然地,比较两个列表的任何东西都是可以接受的,但是比较两个Seq[Int]可以接受的东西的逻辑是什么?

注意seqOrder的定义中,被比较的事物如何成为其参数。显然,List[Int]可以是期望Seq[Int]的参数。由此可以得出,可以比较Seq[Int]的东西代替可以比较List[Int]的东西:它们都可以使用相同的参数。

反向呢?假设我有一个只比较::(列表的缺点)的方法,该方法与Nil一起是List的子类型。我显然不能使用它,因为smaller可能会收到一个Nil进行比较。因此,不能使用Order[::[Int]]代替Order[List[Int]]

让我们继续平等,并为它写一个方法:
def equalLists(a: List[Int], b: List[Int])(implicit eq: Equal[List[Int]]) = eq.equal(a, b)

因为Order扩展了Equal,所以我可以将其与上面相同的隐式使用:
scala> equalLists(List(4, 5, 6), List(1, 2, 3)) // we are comparing lengths!
res3: Boolean = true

这里的逻辑是相同的。显然,任何可以判断两个Seq[Int]是否相同的东西都可以判断两个List[Int]是否相同。由此,得出Equal[Seq[Int]] <: Equal[List[Int]],这是正确的,因为Equal是反变的。

关于scala - Scala协方差-现实生活中的例子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8634628/

相关文章:

scala - 对于元组的理解,withFilter 不是成员错误

scala - sbt testOnly 带有标签的排除列表不起作用

scala - SBT:可以从磁盘读取变量吗?

scala - 从 Scala 的类型获取 ParameterizedType?

闭包和上下文无关语法

javascript - 在具有不同值的对象数组中查找对象的最有效方法是什么?

c++ - 多态和重载有什么区别?

session - 在 Lift Scala 中存储 session 变量

javascript - 如何用尾递归重写这个函数

python - 在每个可能的组合中调用函数