Scala의 불변 집합이 유형에서 공변이 아닌 이유는 무엇입니까?


94

편집 : 원래 답변을 기반 으로이 질문을 다시 작성

scala.collection.immutable.Set클래스의 형식 매개 변수의 공변되지 않습니다. 왜 이런거야?

import scala.collection.immutable._

def foo(s: Set[CharSequence]): Unit = {
    println(s)
}

def bar(): Unit = {
   val s: Set[String] = Set("Hello", "World");
   foo(s); //DOES NOT COMPILE, regardless of whether type is declared 
           //explicitly in the val s declaration
}

foo(s.toSet[CharSequence])잘 컴파일 된다는 점은 주목할 가치가 있습니다. toSet단지 랩 - 메소드는 O (1)이다 asInstanceOf.
john sullivan

1
foo(Set("Hello", "World"))Scala가 올바른 유형의 Set을 추론 할 수있는 것처럼 보이므로 2.10 에서도 컴파일됩니다. 그러나 암시 적 변환에서는 작동하지 않습니다 ( stackoverflow.com/questions/23274033/… ).
LP_ 2014

답변:


55

Set함수로서의 집합 뒤에있는 개념 때문에 유형 매개 변수가 변하지 않습니다. 다음 서명은 내용을 약간 명확히해야합니다.

trait Set[A] extends (A=>Boolean) {
  def apply(e: A): Boolean
}

경우 Set에 공변 있었다 Aapply방법은 유형의 매개 변수를 사용 할 수없는 것 A때문에 함수의 contravariance에. Set잠재적으로있을 수 contravariant 에서 A,하지만 당신은 이런 일을 할 때이 역시 문제가 발생 :

def elements: Iterable[A]

요컨대, 가장 좋은 해결책은 불변 데이터 구조에 대해서도 불변을 유지하는 것입니다. immutable.Map유형 매개 변수 중 하나에서도 불변 임을 알 수 있습니다.


4
나는이 주장이 "함수로서의 집합이면의 개념"에 달려 있다고 생각한다-이것이 확장 될 수 있을까? 예를 들어, "함수로 집합"이 "컬렉션으로 집합"이 아닌 어떤 이점을 제공합니까? 그 공변 유형의 사용을 잃을 가치가 있습니까?
oxbow_lakes

23
형식 서명은 다소 약한 예입니다. 세트의 "apply"는 contains 메소드와 동일합니다. 아아, Scala의 목록은 공 변형이며 contains 메소드도 있습니다. 물론 List의 포함에 대한 서명은 다르지만 메서드는 Set의 경우처럼 작동합니다. 따라서 디자인 결정을 제외하고는 세트가 공변이되는 것을 막을 수있는 것은 없습니다.
Daniel C. Sobral

6
집합은 수학적 관점에서 볼 때 부울 함수가 아닙니다. 세트는 일부 포함 기능에 의해 감소 되지 않는 Zermelo-Fraenkel 공리에서 "구축"됩니다 . 그 뒤에있는 이유는 Russell의 역설입니다. 어떤 것이 세트의 구성원이 될 수 있다면 자신의 구성원이 아닌 세트의 R 세트를 고려하십시오. 그런 다음 R이 R의 구성원입니까?
oxbow_lakes

12
나는 여전히 공분산을 희생하는 것이 Set에 가치가 있다고 확신하지 못합니다. 물론 술어라는 것은 좋지만, 일반적으로 좀 더 장황하고 "set"보다는 "set.contains"를 사용할 수 있습니다 (그리고 "set.contains"는 어쨌든 많은 경우에 더 잘 읽습니다).
Matt R

4
@Martin : List의 contains 메소드는 A가 아닌 Any를 취하기 때문입니다. 유형은 List(1,2,3).contains _is (Any) => Boolean이고 유형은 Set(1,2,3).contains _입니다 res1: (Int) => Boolean.
세스 Tisue

52

http://www.scala-lang.org/node/9764 마틴 오더 스키 글 :

"세트 문제에 관해서는, 비 변형도 구현에서 비롯된다고 생각합니다. 공통 세트는 키 유형의 비 변형 배열 인 해시 테이블로 구현됩니다. 약간 성가신 불규칙성이라는 데 동의합니다."

따라서 이것에 대한 원칙적인 이유를 구성하려는 우리의 모든 노력은 잘못된 것 같습니다 :-)


1
그러나 일부 시퀀스는 배열로도 구현되고 여전히 Seq공변입니다.
LP_ 2014

4
이것은 Array[Any]내부 에 저장함으로써 사소하게 해결할 수 있습니다 .
rightfold

@rightfold가 정확합니다. 합리적인 이유가 있을지 모르지만 그렇지 않습니다.
Paul Draper

6

편집 :이 답변이 주제에서 약간 벗어난 이유를 궁금해하는 사람은 질문자가 질문을 수정했기 때문입니다.

Scala의 유형 추론은 일부 상황에서 문자열이 아닌 CharSequences를 원한다는 것을 파악하기에 충분합니다. 특히 다음은 2.7.3에서 저에게 효과적입니다.

import scala.collections.immutable._
def findCharSequences(): Set[CharSequence] = Set("Hello", "World")

immutable.HashSets를 직접 만드는 방법에 관해서는 :하지 마십시오. 구현 최적화로서, 5 개 미만의 요소의 immutable.HashSets는 실제로 immutable.HashSet의 인스턴스가 아닙니다. EmptySet, Set1, Set2, Set3 또는 Set4입니다. 이러한 클래스는 immutable.Set 하위 클래스이지만 immutable.HashSet은 아닙니다.


당신이 옳습니다. 내 실제 예제를 단순화하기 위해 노력하는 나는 사소한 실수를 :-( 만들어
oxbow_lakes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.