Scala 2.8에서 <: <, <% <및 = : =은 무엇을 의미하며 어디에 기록되어 있습니까?


201

Predef 의 API 문서 에서 일반 함수 유형 (From) => To의 서브 클래스 임을 알 수 있지만 그게 전부입니다. 음? 어딘가에 문서가있을 수 있지만 검색 엔진은 "<: <"와 같은 "이름"을 잘 처리하지 못하므로 찾을 수 없었습니다.

후속 질문 :이 펑키 기호 / 클래스를 언제 사용해야합니까? 왜?


6
여기에 부분적으로 적어도 귀하의 질문에 대답 할 수있는 관련 질문은 stackoverflow.com/questions/2603003/operator-in-scala
Yardena

13
symbolhound.com 은 코드 검색 친구입니다 :)
ron

Haskell의 typeclasses가이 운영자의 업무를 수행합니까? 예 : compare :: Ord a => a -> a -> Ordering? 나는 Haskell 대응과 관련 하여이 Scala 개념을 이해하려고합니다.
케빈 메러디스

답변:


217

이를 일반화 된 유형 제한 조건 이라고 합니다 . 타입 매개 변수화 된 클래스 나 특성 내에서 타입 매개 변수 중 하나 를 추가로 제한 있습니다. 예를 들면 다음과 같습니다.

case class Foo[A](a:A) { // 'A' can be substituted with any type
    // getStringLength can only be used if this is a Foo[String]
    def getStringLength(implicit evidence: A =:= String) = a.length
}

암시 적 인수 evidence는 컴파일러에서 제공합니다 (iff Ais) String. 당신은 그것을 생각할 수있는 증거A 입니다 String고마웠다 인수 자체 만이 존재하는 것을 알고, 중요하지 않습니다. [편집 : 글쎄요, 기술적으로 실제로는 중요합니다.에서 (으) A로의 암시 적 변환을 나타내므로 컴파일러가 String호출 a.length하지 않아도됩니다.]

이제 다음과 같이 사용할 수 있습니다.

scala> Foo("blah").getStringLength
res6: Int = 4

그러나 내가 Foo다른 것을 포함하는 것으로 사용하려고 하면 String:

scala> Foo(123).getStringLength
<console>:9: error: could not find implicit value for parameter evidence: =:=[Int,String]

"Int == String이라는 증거를 찾을 수 없습니다"라는 오류를 읽을 수 있습니다. 일반적으로 요구 되는 것보다 유형에 getStringLength대한 추가 제한 을 부과하고 있습니다 . 즉, 당신은 단지 호출 할 수 켜짐 . 이 제약 조건은 컴파일 타임에 적용되며 멋지다!AFoogetStringLengthFoo[String]

<:<<%<비슷하게 작동하지만, 약간의 변형과 :

  • A =:= B A가 정확히 B 여야 함을 의미
  • A <:< B는 A가 B의 하위 유형이어야 함을 의미합니다 ( 단순 유형 제약 조건 과 유사 <:)
  • A <%< B의미 A는 암시 적 변환을 통해 B 로 볼 수 있어야 함을 의미합니다 (단순한 유형 제약 조건과 유사 <%)

@retronym 의이 스 니펫 은 이러한 종류의 작업을 수행하는 방법과 일반화 된 유형 제약 조건이 이제 더 쉬워지는 방법에 대한 좋은 설명입니다.

추가

당신의 후속 질문에 대답하기 위해, 내가 준 예는 꽤 고안되었으며 분명히 유용하지 않습니다. 그러나 그것을 사용하여 List.sumInts정수 목록을 추가 하는 메소드 와 같은 것을 정의한다고 상상해보십시오 . 이 메소드를 이전의 Lista, 단지 a 에서 호출하는 것을 허용하지 않으려 고 합니다 List[Int]. 그러나 List형식 생성자는 그렇게 제한 될 수 없습니다. 여전히 문자열, foos, bar 및 notnots 목록을 가질 수 있기를 원합니다. 따라서 일반화 된 형식 제약 조건을 설정 sumInts하면 해당 메서드 에만에 사용할 수있는 추가 제약 조건이 있는지 확인할 수 있습니다 List[Int]. 기본적으로 특정 종류의 목록에 대한 특수 사례 코드를 작성하고 있습니다.


3
글쎄,하지만 같은 이름의 방법도 있지만 Manifest언급하지 않았습니다.
Daniel C. Sobral

3
의 방법 Manifest입니다 <:<>:>영업 이익은 일반화 된 형태의 제약 정확히 3 개 품종을 언급 한 이후에만 ..., 나는 그가에 관심이 무엇 있으리라 믿고있어.
톰 크로켓

12
@IttayD : 꽤 영리 ... class =:=[From, To] extends From => To, 어떤 유형의 암시 적 값이 있음을 의미 From =:= To실제로 암시 적 변환 에서 FromTo. 그래서 유형의 암시 적 매개 변수를 받아 들여 A =:= String당신은이 말을하는지 A암시 적으로 변환 할 수 있습니다 String. 당신이 순서를 변경하고 암시 적 인수 형식이어야 한 경우 String =:= A이에서 암시 적 변환이 될 것이기 때문에, 그것은 작동하지 않을 것이다 StringA.
Tom Crockett

25
이 3 자 기호에 이름이 있습니까? Scala의 기호 수프에 대한 나의 문제는 구두로 말하기가 어렵다는 것입니다. 구글이나 다른 검색 엔진을 사용하여 토론과 사용법의 예를 찾는 것은 사실상 불가능합니다.
기가 트론

4
@Andrea Nope, 유형이 정확히 같은 경우에만 작동합니다. From =:= To범위에 암시 적 유형의 값 이 있다는 것은 암시 적 변환이 있음을 의미 From => To하지만 그 의미는 거꾸로 실행되지 않습니다. 암시 적 변환 A => B이 있다고해서 인스턴스가 있음을 의미하지는 않습니다A =:= B . =:=은에 정의 된 봉인 된 추상 클래스 scala.Predef이며 공개적으로 노출 된 인스턴스가 하나만 있으며 이는 암시적이고 유형 A =:= A입니다. 따라서 유형의 내재적 가치가 A =:= BAB동등한 사실을 목격 한다는 보장이 있습니다.
Tom Crockett

55

완전한 대답은 아닙니다 (다른 사람들은 이미 이것에 대답했습니다). 구문을 더 잘 이해하는 데 도움이 될 수있는 다음 사항에 유의하고 싶었습니다.

def getStringLength(implicit evidence: A =:= String)

유형 연산자 에 Scala의 대체 접두사 구문을 사용합니다 .

따라서, A =:= String동일합니다 =:=[A, String](그리고 =:=멋진 이름을 가진 클래스 또는 특성 일뿐입니다). 이 구문은 "일반"클래스에서도 작동합니다. 예를 들어 다음과 같이 작성할 수 있습니다.

val a: Tuple2[Int, String] = (1, "one")

이처럼 :

val a: Int Tuple2 String = (1, "one")

메소드 호출에 대한 "정상"with .()연산자 구문 의 두 구문과 유사 합니다.


2
makes use of Scala's alternative infix syntax for type operators.모든 것이 이해가되지 않는이 설명이 완전히 없어 졌기 때문에
공감해야합니다.

39

이 구성이 무엇인지 이해하려면 다른 답변을 읽으십시오. 여기가 언제 야 당신이 그들을 사용해야합니다. 특정 유형에 대해서만 메소드를 제한해야 할 때 사용합니다.

다음은 예입니다. 다음과 같이 동종 쌍을 정의한다고 가정하십시오.

class Pair[T](val first: T, val second: T)

이제 다음 smaller과 같이 메소드를 추가하려고합니다 .

def smaller = if (first < second) first else second

T주문한 경우에만 작동합니다 . 전체 수업을 제한 할 수 있습니다.

class Pair[T <: Ordered[T]](val first: T, val second: T)

그러나 그것은 부끄러운 것 같습니다- T주문하지 않으면 수업에 사용할 수 있습니다 . 형식 제약 조건을 사용하여 smaller메서드를 계속 정의 할 수 있습니다 .

def smaller(implicit ev: T <:< Ordered[T]) = if (first < second) first else second

전화하지 않는Pair[File], 인스턴스화해도 괜찮습니다. smaller 그것을.

의 경우 Option구현자는 orNull이해가되지 않더라도 메소드를 원했습니다 Option[Int]. 형식 제약 조건을 사용하면 모든 것이 좋습니다. 당신이 사용할 수있는 orNullOption[String], 당신은을 형성 할 수있는 Option[Int]당신이 전화하지 않는 한, 그것은을 사용할 orNull그것을. 시도 Some(42).orNull하면 매력적인 메시지가 나타납니다.

 error: Cannot prove that Null <:< Int

2
나는 이것이 대답 후 몇 년이라는 것을 알고 있지만에 대한 유스 케이스를 찾고 있는데 <:<, Ordered이제는 예제가 더 이상 강렬하지 않다고 생각합니다. 지금부터 특성 Ordering보다는 유형 클래스를 사용하려고 합니다 Ordered. 같은 것 : def smaller(implicit ord: Ordering[T]) = if (ord.lt(first, second)) first else second.
ebruchez

1
@ebruchez : 유스 케이스가 수정되지 않은 스칼라에서 노동 조합 유형을 인코딩을위한 참조 milessabin.com/blog/2011/06/09/scala-union-types-curry-howard

17

사용되는 위치에 따라 다릅니다. 암시 적 매개 변수 유형을 선언하는 동안 사용되는 경우가 대부분 클래스입니다. 드물게 객체 일 수도 있습니다. 마지막으로 이들은 Manifest객체의 연산자가 될 수 있습니다 . 그것들은 scala.Predef특별히 잘 문서화되어 있지는 않지만 처음 두 경우에 내부적으로 정의됩니다 .

그들은, 클래스 사이의 관계를 테스트 단지 같은 방법 제공하기 위해 의미 <:하고 <%후자를 사용할 수없는 경우 상황에서 수행합니다.

"언제 사용해야합니까?"라는 질문에 대해, 당신이 알아야 할 것이 아니라면 대답은하지 말아야합니다. :-) 편집 : 좋아, 좋아, 여기 라이브러리의 예가 있습니다. 에 Either, 당신은 :

/**
  * Joins an <code>Either</code> through <code>Right</code>.
  */
 def joinRight[A1 >: A, B1 >: B, C](implicit ev: B1 <:< Either[A1, C]): Either[A1, C] = this match {
   case Left(a)  => Left(a)
   case Right(b) => b
 }

 /**
  * Joins an <code>Either</code> through <code>Left</code>.
  */
 def joinLeft[A1 >: A, B1 >: B, C](implicit ev: A1 <:< Either[C, B1]): Either[C, B1] = this match {
   case Left(a)  => a
   case Right(b) => Right(b)
 }

Option, 당신은 :

def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null

컬렉션에서 다른 예제를 찾을 수 있습니다.


:-)이들의 또 다른 하나? 그리고 "언제 사용해야합니까?"에 대한 귀하의 답변에 동의합니다. 많은 것들에 적용됩니다.
Mike Miller

"그들은 클래스 사이의 관계를 테스트하는 방법을 제공하기위한 것입니다"<-도움이 되기에는 너무 일반적입니다
Jeff

3
""언제 사용해야합니까? "라는 질문에 대해, 당신이 알아야 할 것이 아니라면 대답은하지 말아야합니다." <-그것이 내가 묻는 이유입니다. 나는 스스로 결정을 내릴 수 있기를 원합니다.
Jeff
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.