为什么要设置功能? [英] Why is a Set a function?

查看:87
本文介绍了为什么要设置功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Scala中,Set是一个函数:

In Scala a Set is a function:

trait Set[A] extends (A => Boolean)

因为类型A发生在协变位置,所以不可能有协变不变量Set.相反,Seq没有定义为函数.为什么Sets和Seqs这样设计的问题已经有了一些内容:

This make it impossible to have a covariant immutable Set because type A occurs in contravariant position. In contrast Seq is not defined as a function. There is already some content about the question why Sets and Seqs are designed this way:

  • Why is Scala's immutable Set not covariant in its type?
  • Scala: Why does Seq.contains take an Any argument, instead of an argument of the sequence type?
  • Why does Seq.contains accept type Any rather than the type parameter A?

一个答案说,这样做的原因是数学背景.但是,这个答案没有多解释了.那么,将Set定义为函数的具体优点是什么?或者以不同的方式实现它的缺点是什么?

One answer says that the reason for this is the mathematical background. But this answer wasn't explained a little more. So, what are the concrete advantages to define a Set as a function or what would be the disadvantages if it is implemented differently?

推荐答案

类型Set[A]的集合必须具有一种测试类型A的元素是否在集合中的方法.此方法(apply)必须具有表示该元素的类型为A的参数,并且该参数位于变量位置.这意味着集合的类型参数A不能协变.所以-不是函数接口的扩展使不可能具有协变不可变集,而是存在协变apply方法.

The set of type Set[A] has to have a method that tests if an element of type A is in the set. This method (apply) has to have a parameter of type A representing that element, and that parameter is in the contravariant position. This means that sets cannot be covariant in their type parameter A. So - it's not the extending of the function interface that makes it impossible to have covariant immutable sets, it's the existence of the contravariant apply method.

并且出于方便起见,扩展Function1接口是有意义的,以便能够传递集合并将它们视为函数.

And for reasons of convenience, it makes sense to extend the Function1 interface to be able to pass sets around and treat them as functions.

相反,序列抽象没有测试元素是否在序列中的方法,它仅具有索引方法-apply接受整数索引,并在该索引处返回元素.序列也被定义为函数,但是类型为Int => A的函数(在A中是协变的),而不是A => Boolean作为集合.

By contrast, sequence abstraction doesn't have a method that tests if an element is in the sequence, it only has the indexing method - apply takes an integer index, and returns the element at that index. Sequences are also defined as functions, but functions of type Int => A (which are covariant in A), not A => Boolean, as sets.

如果您想了解更多有关如果将集合在其类型参数A中定义为协变的方式将如何破坏类型安全的信息,请参见此示例,其中出于缓存缓存的原因,set实现对私有成员进行了一些写入操作(在@uV下面是禁用方差检查的注释,而expensiveLookup则是为了模拟对某个元素是否在集合中的调用,该调用对计算量大的检查):

If you want to know more about how type safety would be broken if sets were defined as covariant in their type parameter A, see this example in which the set implementation does some writing to private members for reasons of caching the lookups (below @uV is the annotation which disables variance checking and expensiveLookup is meant to simulate a call to a computationally expensive check if an element is in the set):

import annotation.unchecked.{uncheckedVariance => uV}

trait Set[+A] {
  def apply(elem: A @uV): Boolean
}

class CachingSet[+A >: Null] extends Set[A] {
  private var lastLookup: (A @uV, Boolean) = (null, false)
  private def expensiveLookup(elem: A @uV) = (elem, true)
  def apply(elem: A @uV): Boolean = {
    if (elem != lastLookup._1) lastLookup = expensiveLookup(elem)
    lastLookup._2
  }
  def lastQueriedElement: A = lastLookup._1
}

object Main extends App {
  val css = new CachingSet[String]
  val csa: CachingSet[AnyRef] = css

  csa.apply(new AnyRef)
  val s: String = css.lastQueriedElement // you'll get a ClassCastException here
}

这篇关于为什么要设置功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆