我了解scala中的协方差和自变量。协方差在现实世界中有很多应用程序,但是对于函数协方差应用程序,除了函数的相同旧示例,我想不出任何东西。
有人可以阐明的真实世界示例的用法吗?
最佳答案
我认为,Function
之后的两个最简单的示例是排序和相等。但是,第一个在Scala的标准库中不是反变量,而第二个甚至不存在于其中。因此,我将使用Scalaz等效项:Order和Equal。
接下来,我需要一些类层次结构,最好是一个熟悉的类层次结构,当然,以上两个概念都必须对此有意义。如果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/