복붙노트

[SCALA] 어떻게 기능의 요소의 공변 및 contravariant 위치를 확인하려면?

SCALA

어떻게 기능의 요소의 공변 및 contravariant 위치를 확인하려면?

이것은 내가 스칼라 contravariance 및 공분산에 대한 읽을 수있는 기사 중 하나에서 코드 조각입니다. 공변 A 형은 값 pet2의 A 형에 contravariant 위치에서 발생 그러나, 나는 스칼라 컴파일러 "오류가 발생합니다 오류 메시지를 이해하지 못하는

class Pets[+A](val pet:A) {
  def add(pet2: A): String = "done"
}

이 코드의 나의 이해는 공변하고 그러나 A의 아형 개체를 받아들이는 애완 동물, 기능 추가가 애완 동물 유형 A와 부속 유형의 매개 변수를 취할 수있는 A 형 only.Being 공변 수단의 매개 변수에 걸리는 것입니다. 그런 다음이 오류가 발생하는 방법을 생각한다. 어디에서 심지어 발생 contravariance의 문제이다.

위의 오류 메시지에 대한 모든 설명은 매우 도움이 될 것입니다. 감사

해결법

  1. ==============================

    1.TL; DR :

    TL; DR :

    유일하게 남아있는 가능성이 : 애완 동물 A.에서 일정해야합니다

    나는 개선 및 훨씬 더 제시하는이 기회를 사용합니다 이 만화의 엄격한 버전. 그것은 공분산 및 contravariance의 그림입니다 하위 유형 및 신고 사이트 분산 주석과 프로그래밍 언어에 대한 개념 (분명히, 심지어 자바 사람들은 충분히 계몽 발견  문제는) 사용 현장의 변화에 ​​대한 있다는 사실에도 불구하고.

    첫째, 그림 :

    이제 컴파일 가능한 스칼라 코드에 대한 자세한 설명.

    매우 구체적으로, 매우 일반적인에서, 에너지 원의 다음과 같은 계층 구조를 고려 :

    class EnergySource
    class Vegetables extends EnergySource
    class Bamboo extends Vegetables
    

    이제 특성 소비자를 고려 [-A] 하나의 소비가 그 (A : A) -method :

    trait Consumer[-A] {
      def consume(a: A): Unit
    }
    

    이제이 특성의 몇 가지 예를 구현 보자 :

    object Fire extends Consumer[EnergySource] {
      def consume(a: EnergySource): Unit = a match {
        case b: Bamboo => println("That's bamboo! Burn, bamboo!")
        case v: Vegetables => println("Water evaporates, vegetable burns.")
        case c: EnergySource => println("A generic energy source. It burns.")
      }
    }
    
    object GeneralistHerbivore extends Consumer[Vegetables] {
      def consume(a: Vegetables): Unit = a match {
        case b: Bamboo => println("Fresh bamboo shoots, delicious!")
        case v: Vegetables => println("Some vegetables, nice.")
      }
    }
    
    object Panda extends Consumer[Bamboo] {
      def consume(b: Bamboo): Unit = println("Bamboo! I eat nothing else!")
    }
    

    이제, 왜 소비자가에 contravariant해야합니까? 인스턴스화하는하자의 시도 몇 가지 다른 에너지 원하고 다양한 소비자에게 공급 :

    val oilBarrel = new EnergySource
    val mixedVegetables = new Vegetables
    val bamboo = new Bamboo
    
    Fire.consume(bamboo)                // ok
    Fire.consume(mixedVegetables)       // ok
    Fire.consume(oilBarrel)             // ok
    
    GeneralistHerbivore.consume(bamboo)           // ok
    GeneralistHerbivore.consume(mixedVegetables)  // ok
    // GeneralistHerbivore.consume(oilBarrel)     // No! Won't compile
    
    Panda.consume(bamboo)               // ok
    // Panda.consume(mixedVegetables)   // No! Might contain sth Panda is allergic to
    // Panda.consume(oilBarrel)         // No! Pandas obviously cannot eat crude oil
    

    결과는 다음과 같습니다 GeneralistHerbivore이 소비 할 수있는 화재는 모든 것을 소비 할 수있는, 차례로 GeneralistHerbivore는 팬더가 먹을 수있는 모든 것을 소비 할 수 있습니다. 따라서만큼 우리는 에너지를 소비 할 수있는 능력에 대해 신경으로, 소비자가 [야채]가 요구되는 경우 소비자는 [EnergySource 같이, 치환 될 수있는 과 소비자 [대나무]가 요구되는 경우 소비자는 [야채]는 치환 될 수있다. 따라서, 의미가 그 소비자 [EnergySource] <: 소비자 [야채] 및 소비자 [야채] <: 소비자 [대나무]에도 관계하지만 사이 유형 매개 변수는 정반대입니다 :

    type >:>[B, A] = A <:< B
    
    implicitly:          EnergySource  >:>          Vegetables
    implicitly:          EnergySource                           >:>          Bamboo
    implicitly:                                     Vegetables  >:>          Bamboo
    
    implicitly: Consumer[EnergySource] <:< Consumer[Vegetables]
    implicitly: Consumer[EnergySource]                          <:< Consumer[Bamboo]
    implicitly:                            Consumer[Vegetables] <:< Consumer[Bamboo]
    

    제품의 계층 구조를 정의합니다 :

    class Entertainment
    class Music extends Entertainment
    class Metal extends Music // yes, it does, seriously^^
    

    A 형의 값을 생성 할 수있는 특성을 정의합니다 :

    trait Producer[+A] {
      def get: A
    }
    

    다양한 "소스"전문 다양한 수준의 / "생산자"를 정의합니다 :

    object BrowseYoutube extends Producer[Entertainment] {
      def get: Entertainment = List(
        new Entertainment { override def toString = "Lolcats" },
        new Entertainment { override def toString = "Juggling Clowns" },
        new Music { override def toString = "Rick Astley" }
      )((System.currentTimeMillis % 3).toInt)
    }
    
    object RandomMusician extends Producer[Music] {
      def get: Music = List(
        new Music { override def toString = "...plays Mozart's Piano Sonata no. 11" },
        new Music { override def toString = "...plays BBF3 piano cover" }
      )((System.currentTimeMillis % 2).toInt)
    }
    
    object MetalBandMember extends Producer[Metal] {
      def get = new Metal { override def toString = "I" }
    }
    

    BrowseYoutube 엔터테인먼트의 가장 일반적인 소스입니다 : 그것은 당신에게 줄 수 엔터테인먼트 기본적으로 어떤 종류 : 고양이 비디오, 저글링 광대, 또는 (실수로) 어떤 음악. 엔터테인먼트의이 일반적인 소스는 그림 1의 원형 적 광대로 표시됩니다.

    RandomMusician 이미 다소 적어도 우리는이 객체가 알고, 전문 (특정 장르에 제한이 없다하더라도) 음악을 생산하고 있습니다.

    마지막으로, MetalBandMember는 매우 전문 : get 메소드가 리턴에 보장 금속 음악 만 매우 구체적인 종류.

    이제이 세 가지 목적에서 엔터테인먼트의 다양한 종류를 얻으려고하자 :

    val entertainment1: Entertainment = BrowseYoutube.get   // ok
    val entertainment2: Entertainment = RandomMusician.get  // ok
    val entertainment3: Entertainment = MetalBandMember.get // ok
    
    // val music1: Music = BrowseYoutube.get // No: could be cat videos!
    val music2: Music = RandomMusician.get   // ok
    val music3: Music = MetalBandMember.get  // ok
    
    // val metal1: Entertainment = BrowseYoutube.get   // No, probably not even music
    // val metal2: Entertainment = RandomMusician.get  // No, could be Mozart, could be Rick Astley
    val metal3: Entertainment = MetalBandMember.get    // ok, because we get it from the specialist
    

    우리는 세 가지 프로듀서 [엔터테인먼트], 프로듀서 [음악]와 프로듀서 [금속] 엔터테인먼트의 어떤 종류를 생산할 수있는 것을 알 수있다. 우리는 단지 프로듀서 [음악]와 프로듀서 [금속] 농산물 음악에 보장을 참조하십시오. 마지막으로, 우리는 매우 전문 프로듀서가 [금속]이 보장되는 것을 볼 수 금속 및 아무것도를 생산하고 있습니다. 따라서, 생산자 [음악] 및 프로듀서 [금속]는 치환 될 수있는 프로듀서 대 [엔터테인먼트]. 프로듀서 [금속]가 프로듀서 [음악]로 치환 될 수있다. 일반, 프로듀서에서 제품에 대한보다 구체적인 종류는 덜 전문 프로듀서 녹실 할 수 있습니다 :

    implicitly:          Metal  <:<          Music
    implicitly:          Metal                      <:<          Entertainment
    implicitly:                              Music  <:<          Entertainment
    
    implicitly: Producer[Metal] <:< Producer[Music]
    implicitly: Producer[Metal]                     <:< Producer[Entertainment]
    implicitly:                     Producer[Music] <:< Producer[Entertainment]
    

    제품 하위 유형 간의 관계는 하위 유형 간의 관계와 동일 제품의 생산. 이것은 무엇 공분산 방법이다.

    관련된 링크들

  2. ==============================

    2.(가 + A로 표시 있기 때문에) 클래스 애완 동물은 A 형에 공변입니다,하지만 당신은 contravariant 위치에 그것을 사용하고 있습니다. 이 스칼라 함수의 특성을 살펴 경우, 당신은 반환 형식은 공변 상태에서 입력 매개 변수 유형, contravariant 것을 볼 수 있기 때문이다. 모든 함수는 반환 형식에 입력 유형에 contravariant과 공변입니다.

    (가 + A로 표시 있기 때문에) 클래스 애완 동물은 A 형에 공변입니다,하지만 당신은 contravariant 위치에 그것을 사용하고 있습니다. 이 스칼라 함수의 특성을 살펴 경우, 당신은 반환 형식은 공변 상태에서 입력 매개 변수 유형, contravariant 것을 볼 수 있기 때문이다. 모든 함수는 반환 형식에 입력 유형에 contravariant과 공변입니다.

    예를 들어, 하나 개의 인수를 복용 함수는 다음과 같이 정의되어있다

    trait Function1[-T1, +R]
    

    함수는 함수 F의 하위 유형으로 S에 대한 건은, 그것은 "이하 (같거나)이 필요하고 더 (동일하거나)를 제공"할 필요가있다. 이 또한 Liskov 대체 원칙으로 알려져있다. 실제로,이 방법은 함수의 특성 요구는 출력 및 입력에 공변 contravariant 될 것이다. (우리는 제한, 예컨대 과일에서 식품을 완화하기 때문에 여기에서 "낮은"수단 "수퍼")를 그 어느 T1 또는 슈퍼 타입 중 하나를 수용하기 때문에 입력에 contravariant 존재함으로써 "동일 이하"이 필요하다. 또한, 자사의 반환 형식에서 공변 인으로, 우리가 과일에서 예를 들어, 더 많은 정보를 추가하고 있기 때문에 "더"수단 "하위"여기 (보다 R을 반환하거나 아무것도 더 구체적인 수 있다는 것을 의미한다 "동일하거나 더"요구 사과).

    그런데 왜? 왜 다른 방법의 주위에? 여기에 희망을보다 직관적으로 설명 할 것입니다 예입니다 - 두 개의 콘크리트 기능, 다른 하나 개 존재 하위 유형을 상상은 :

    val f: Fruit => Fruit
    val s: Food => Apple
    

    덜 (과일에서 식품에가는 우리 "잃게"정보)를 필요로하고 더 (과일에서 애플에가는 우리 "이득"정보)를 제공하기 때문에 기능들, 함수 f에 대한 유효한 하위 유형이다. s는 F의 입력 형식 (contravariance)의 슈퍼의 입력 형태를 가지고, 그것은 F의 복귀 형 (공분산)의 부속의 타입을 반환하는 방법을 참고. 이제 이러한 기능을 사용하는 코드의 조각을 가정 해 봅시다 :

    def someMethod(fun: Fruit => Fruit) = // some implementation
    

    둘 것으로 someMethod (F)와 것으로 someMethod (들) 유효 호출합니다. 방법 것으로 someMethod 그것에 열매를 적용하고, 그것에서 열매를받을 내부적으로 재미를 사용합니다. 의 우리가 식품을 공급할 수있는 수단은 F의 서브 타입이기 때문에 => 애플의 재미를 완벽하게 좋은 예를 역할을합니다. 것으로 someMethod 내부 코드 것이다 재미 음식을 취하고, 과일 음식이기 때문에, OK 일부 과일, 몇 가지 점 피드 재미에서. 재미 과일을 반환해야하기 때문에 다른 한편으로는, 반환 형식으로 애플을 재미, 좋은 또한, 사과를 반환하여 그 계약을 준수합니다.

    나는 그것을 조금 명확하게 관리하겠습니다 더 질문을 주시기 바랍니다.

  3. from https://stackoverflow.com/questions/48812254/how-to-check-covariant-and-contravariant-position-of-an-element-in-the-function by cc-by-sa and MIT license