복붙노트

[SCALA] 의존하는 방법의 유형에 대한 몇 가지 매력적인 사용 사례는 무엇입니까?

SCALA

의존하는 방법의 유형에 대한 몇 가지 매력적인 사용 사례는 무엇입니까?

이전 실험적인 기능으로 사용 종속 방법의 유형은 이제 트렁크에 기본적으로 사용되었으며, 분명히이 스칼라 지역 사회에 어떤 흥분을 만든 것으로 보인다.

첫번째보기에, 그것은이 유용 할 수있는 것을 즉시 분명 아니다. HEIKO Seeberger는 주석에서 볼 수 있듯이 쉽게 방법에 대한 형식 매개 변수가 재현 할 수있는, 여기에 의존하는 방법 유형의 간단한 예제를 기록했다. 그래서 매우 강력한 예 아니었다. (내가 뭔가를 분명 누락 될 수 있습니다. 저 그렇다면 수정하십시오.)

그들은 명확하게 대안보다 유리하다 의존하는 방법 유형에 대한 사용 사례 중 일부 실용적이고 유용한 예는 무엇인가?

우리는 전에 쉽게 / 수 없었던 그들과 함께 흥미로운 어떤 일을 할 수 있습니까?

그들은 기존의 타입 시스템 기능을 통해 우리를 어떻게 구입합니까?

또한, 종속 방법의 유형은 하스켈, OCaml의 다른 고급 입력 된 언어의 유형 시스템에있는 모든 기능에서 유사 또는 도면 영감을?

해결법

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

    1.회원의 더 많은 이하의 모든 사용 (예. 중첩) 형태의 종속 방법의 유형에 대한 필요성을 야기 할 수 있습니다. 특히, 나는 따라 방법의 유형없이 고전 케이크 패턴이 안티 패턴 인에 가까운 것을 유지한다.

    회원의 더 많은 이하의 모든 사용 (예. 중첩) 형태의 종속 방법의 유형에 대한 필요성을 야기 할 수 있습니다. 특히, 나는 따라 방법의 유형없이 고전 케이크 패턴이 안티 패턴 인에 가까운 것을 유지한다.

    그래서 문제는 무엇인가? 스칼라의 중첩 유형은 둘러싸는 경우에 따라 달라집니다. 따라서, 종속 방법 유형의 부재, 절망적 어려울 수 인스턴스 외부에서 사용하려고. 이것은 초기에 우아하고 악몽 단단하고 리팩토링하기 어려운 기형에 호소하는 것 디자인을 해제 할 수 있습니다.

    나는, 내 고급 스칼라 교육 과정 제공 운동과 그 설명하겠습니다

    trait ResourceManager {
      type Resource <: BasicResource
      trait BasicResource {
        def hash : String
        def duplicates(r : Resource) : Boolean
      }
      def create : Resource
    
      // Test methods: exercise is to move them outside ResourceManager
      def testHash(r : Resource) = assert(r.hash == "9e47088d")  
      def testDuplicates(r : Resource) = assert(r.duplicates(r))
    }
    
    trait FileManager extends ResourceManager {
      type Resource <: File
      trait File extends BasicResource {
        def local : Boolean
      }
      override def create : Resource
    }
    
    class NetworkFileManager extends FileManager {
      type Resource = RemoteFile
      class RemoteFile extends File {
        def local = false
        def hash = "9e47088d"
        def duplicates(r : Resource) = (local == r.local) && (hash == r.hash)
      }
      override def create : Resource = new RemoteFile
    }
    

    그것은 고전적인 케이크 패턴의 예 : 우리는 점차적으로 계층 구조를 통해 정제하는 추상화의 가족이 (ResourceManager에 / 자원은 파일 관리자 / NetworkFileManager / RemoteFile을에 의해 정제 차례에있는 파일에 의해 정제된다). 그것은 장난감 예,하지만 패턴은 진짜 : 그것은 스칼라 컴파일러 전반에 걸쳐 사용되는 및 스칼라 이클립스 플러그인에서 광범위하게 사용되었다.

    여기에 사용되는 추상화의 예입니다,

    val nfm = new NetworkFileManager
    val rf : nfm.Resource = nfm.create
    nfm.testHash(rf)
    nfm.testDuplicates(rf)
    

    경로 의존성은 컴파일러가 NetworkFileManager에 testHash 및 testDuplicates 방법에만 즉, 그것에 대응하는 인수로 호출 할 수 있음을 보증한다는 것을 의미합니다. 그것은 자신의 RemoteFiles 원격 및 다른 아무것도입니다.

    그건 부정 할 바람직한 특성,하지만 우리는 다른 소스 파일이 테스트 코드를 이동하고 싶었 가정 해 봅시다? 의존하는 방법의 유형으로는 ResourceManager에 계층 구조 외부에서 그 방법을 재정의 할 하찮게 쉽게,

    def testHash4(rm : ResourceManager)(r : rm.Resource) = 
      assert(r.hash == "9e47088d")
    
    def testDuplicates4(rm : ResourceManager)(r : rm.Resource) = 
      assert(r.duplicates(r))
    

    여기 의존적 방법 유형의 용도를 참고 번째 인수 (rm.Resource)의 형태는 첫 번째 인수 (RM)의 값에 의존한다.

    의존하는 방법의 유형없이이 작업을 수행 할 수 있지만 그것은 매우 어색하고 메커니즘은 매우 직관적이다 : 지금 거의 2 년 동안이 과정을 가르치고 있었고, 그 시간에, 아무도는 표시하지 않고 작업 솔루션에 도달했습니다.

    자신을 위해 그것을 시도 ...

    // Reimplement the testHash and testDuplicates methods outside
    // the ResourceManager hierarchy without using dependent method types
    def testHash        // TODO ... 
    def testDuplicates  // TODO ...
    
    testHash(rf)
    testDuplicates(rf)
    

    그것으로 어려움을 겪고있는 동안 잠시 후 당신은 내가 왜 운명의 베이커리 전화 (또는 어쩌면 데이빗 맥 이버했다, 우리가 용어를 만들어 낸 우리의 어떤 기억이 안나요) 아마를 발견 할 것이다.

    편집 : 합의가 운명의 빵집은 데이빗 맥 이버의 주화했다입니다 ...

    보너스의 경우 : 일반 (그것의 일부로 종속 방법의 종류)에 따라 종류의 스칼라의 형태로 프로그래밍 언어 베타에 의해 영감을했다 ... 그들은 베타의 일관성을 중첩 의미에서 자연적으로 발생한다. 나는이 양식에 따라 종류가 다른 경우에도 희미하게 주류 프로그래밍 언어를 알고하지 않습니다. COQ, 카이엔, 경구 및 AGDA 같은 언어보다 일반적인 몇 가지 방법에 따라 입력의 다른 형태를 가지고 있지만, 스칼라는 달리, 하위 유형이없는, 타입 시스템의 일원에 의해 크게 차이가있다.

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

    2.

    trait Graph {
      type Node
      type Edge
      def end1(e: Edge): Node
      def end2(e: Edge): Node
      def nodes: Set[Node]
      def edges: Set[Edge]
    }
    

    다른 곳에서 우리는 정적으로 우리가 예컨대, 두 개의 서로 다른 그래프에서 노드를 혼합되지 않도록 보장 할 수 있습니다 :

    def shortestPath(g: Graph)(n1: g.Node, n2: g.Node) = ... 
    

    물론, 이것은 이미 그래프 내에서 정의 된 경우 일했다,하지만 우리는 그래프를 수정할 수 있으며 대해 "내 라이브러리 포주"확장자를 작성 말한다.

    두 번째 질문에 대해이 기능으로 사용 유형이 완료 의존 유형보다 훨씬 약하다. (그 맛에 대한 AGDA에 의존적으로 입력 된 프로그래밍 참조) 나는 전에 비유를 본 적이 생각하지 않습니다.

  3. ==============================

    3.콘크리트 추상 형식의 멤버는 형식 매개 변수 대신 사용하는 경우이 새로운 기능이 필요하다. 입력 매개 변수가 사용되는 경우, 가족 다형 형 의존성을 최신으로 표현 될 수 있고, 다음의 단순화 된 예와 스칼라 일부 이전 버전.

    콘크리트 추상 형식의 멤버는 형식 매개 변수 대신 사용하는 경우이 새로운 기능이 필요하다. 입력 매개 변수가 사용되는 경우, 가족 다형 형 의존성을 최신으로 표현 될 수 있고, 다음의 단순화 된 예와 스칼라 일부 이전 버전.

    trait C[A]
    def f[M](a: C[M], b: M) = b
    class C1 extends C[Int]
    class C2 extends C[String]
    
    f(new C1, 0)
    res0: Int = 0
    f(new C2, "")
    res1: java.lang.String = 
    f(new C1, "")
    error: type mismatch;
     found   : C1
     required: C[Any]
           f(new C1, "")
             ^
    
  4. ==============================

    4.나는 환경 상태 선언적 프로그래밍의 한 형태의 interoption에 대한 모델을 개발하고 있어요. 세부 사항은 여기에 관련이없는, (예를 들어, 시리얼과 함께 액터 모델에 콜백과 개념의 유사성에 대한 자세한 내용).

    나는 환경 상태 선언적 프로그래밍의 한 형태의 interoption에 대한 모델을 개발하고 있어요. 세부 사항은 여기에 관련이없는, (예를 들어, 시리얼과 함께 액터 모델에 콜백과 개념의 유사성에 대한 자세한 내용).

    관련 문제는 상태 값이 해시 맵에 저장 해시 키 값을 참조하는 것입니다. 환경에서 값이되는 함수 입력 불변 인자, 등의 기능을 호출하고, 환경의 상태를 기록 할 수있다. 그러나 기능은 환경의 값을 판독 할 수 없다 (따라서 함수의 내부 코드는 상태 변경의 순서에 의존하지 않기 때문에 그 의미 선언적 유지). 어떻게 스칼라이를 입력합니다?

    환경 클래스는 호출 등의 기능을 입력하고 함수의 인수의 해시 키를 입력 오버로드 방법이 있어야합니다. 따라서,이 방법은 값 공개 판독 액세스를 제공하지 않고, 해시 맵에서 필요한 값으로 함수를 호출 할 수있다 (따라서 기능을 환경의 값을 판독 할 수있는 능력을 거부 필요).

    이 해시 키는 문자열이나 정수 해시 값, 해시 맵 요소 유형의 정적 타이핑는하지만 즉이 가능한 것, 모든 또는 AnyRef (해시 맵 코드가 아닙니다 아래 그림 참조)에 포섭, 따라서 런타임 불일치가 발생할 수 있습니다 주어진 해시 키에 대한 해시 맵에 모든 유형의 값을 넣어.

    trait Env {
    ...
      def callit[A](func: Env => Any => A, arg1key: String): A
      def callit[A](func: Env => Any => Any => A, arg1key: String, arg2key: String): A
    }
    

    내가 classOf를 사용하는 런타임에 클래스 이름의 해시 키를 얻을 수있는 이론적으로 다음을 테스트하지 않았기 때문에 해시 키 대신 문자열의 클래스 이름이지만 (스칼라의 역 따옴표를 사용하여 클래스 이름의 문자열을 포함하는) .

    trait DependentHashKey {
      type ValueType
    }
    trait `the hash key string` extends DependentHashKey {
      type ValueType <: SomeType
    }
    

    그래서 정적 유형의 안전이 달성된다.

    def callit[A](arg1key: DependentHashKey)(func: Env => arg1key.ValueType => A): A
    
  5. from https://stackoverflow.com/questions/7860163/what-are-some-compelling-use-cases-for-dependent-method-types by cc-by-sa and MIT license