Haskell Language
타이핑 된 구멍
수색…
비고
하스켈의 강점 중 하나는 타입 시스템에서 타입 도메인을 사용하여 문제 도메인의 일부를 모델링 할 수있는 능력입니다. 그렇게하는 과정에서 종종 매우 복잡한 유형을 접하게됩니다. 이러한 유형 (즉, 이러한 유형의 값을 가진 프로그램)을 작성할 때 모든 유형의 '저글링'이 거의 불가능해질 수 있습니다. GHC 7.8부터는 형식화 된 구멍이라는 새로운 구문 기능이 있습니다. 형식화 된 구멍은 핵심 언어의 의미를 변경하지 않습니다. 그들은 순수하게 프로그램을 작성하는 데 도움을주기위한 것입니다.
입력 된 구멍에 대한 자세한 설명과 입력 된 구멍의 디자인에 대한 설명은 Haskell 위키를 참조하십시오.
입력 된 구멍 에 관한 GHC 사용자 안내서의 섹션.
입력 된 구의 구문
입력 된 구멍은 표현식 컨텍스트에서 범위에없는 단일 밑줄 ( _
) 또는 유효한 하스켈 식별자입니다. 입력 된 구멍이 존재하기 전에이 두 가지 모두 오류를 유발하므로 새로운 구문이 이전 구문을 간섭하지 않습니다.
입력 된 구멍의 동작 제어
입력 된 구멍의 기본 동작은 입력 된 구멍이있을 때 컴파일 타임 오류를 생성하는 것입니다. 그러나 행동을 미세 조정할 수있는 몇 가지 플래그가 있습니다. 이러한 플래그는 다음과 같이 요약됩니다 ( GHC trac ).
기본적으로 GHC는 입력 된 구멍을 입력하고 입력 된 구멍을 만났을 때 컴파일 오류를 생성합니다.
-fdefer-type-errors
또는-fdefer-typed-holes
을 사용하면 구멍 오류가 경고로 변환되고 평가시 런타임 오류가 발생합니다.
-fwarn-typed-holes
경고 플래그는 기본적으로 설정됩니다.-fdefer-type-errors
또는-fdefer-typed-holes
하지 않으면이 조건에서 입력 된 구멍이 오류-fdefer-typed-holes
플래그는 작업 없음입니다. 지연 플래그 중 하나가 사용 가능하면 (유형이 지정된 홀 오류를 경고로 변환하는 경우)-fno-warn-typed-holes
플래그는 경고를 사용 불가능하게합니다. 이는 컴파일이 자동으로 성공하고 구멍을 평가하면 런타임 오류가 발생 함을 의미합니다.
타이핑 된 구멍의 의미
타입 구멍의 값은 타입 undefined
된 구멍이 컴파일 타임 에러를 유발하지만 간단히 말해서 undefined
않았다고 말할 수 있으므로, 값을 할당 할 필요는 없습니다. 그러나 입력 된 구멍 (활성화 된 경우)은 입력 된 구멍의 이름, 추정 된 가장 일반적인 형식 및 모든 로컬 바인딩의 형식을 나타내는 컴파일 시간 오류 (지연된 형식 오류가있는 경고)를 생성합니다. 예 :
Prelude> \x -> _var + length (drop 1 x)
<interactive>:19:7: Warning:
Found hole `_var' with type: Int
Relevant bindings include
x :: [a] (bound at <interactive>:19:2)
it :: [a] -> Int (bound at <interactive>:19:1)
In the first argument of `(+)', namely `_var'
In the expression: _var + length (drop 1 x)
In the expression: \ x -> _var + length (drop 1 x)
위와 같이 GHCi repl에 입력 된 표현식에 입력 된 구멍의 경우 입력 된 표현식의 유형도보고 it
(여기서 유형 [a] -> Int
).
입력 된 구멍을 사용하여 클래스 인스턴스 정의
입력 된 구멍을 사용하면 대화식 프로세스를 통해 함수를 쉽게 정의 할 수 있습니다.
클래스 인스턴스 Foo Bar
( Foo
인스턴스가 필요한 일부 다형성 라이브러리 함수와 함께 사용하기 위해 사용자 정의 Bar
유형 용)를 정의한다고 가정 해보십시오. 이제 전통적으로 Foo
의 문서를 살펴보고, 정의 할 필요가있는 메서드를 파악하고, 형식을 조사합니다. 그러나 형식화 된 구멍을 사용하면 실제로 건너 뛸 수 있습니다!
먼저 더미 인스턴스를 정의하십시오.
instance Foo Bar where
컴파일러는 이제 불평 할 것이다.
Bar.hs:13:10: Warning:
No explicit implementation for
‘foom’ and ‘quun’
In the instance declaration for ‘Foo Bar’
좋습니다, 그래서 우리는 foom
위해 foom
을 정의 할 필요가 Bar
. 그러나도 있어야하는 것이 무엇인가? 다시 우리는 문서를보기에는 너무 게으르다. 컴파일러에게 물어 보자 :
instance Foo Bar where
foom = _
여기서 우리는 입력 된 구멍을 간단한 "문서 쿼리"로 사용했습니다. 컴파일러 출력
Bar.hs:14:10:
Found hole ‘_’ with type: Bar -> Gronk Bar
Relevant bindings include
foom :: Bar -> Gronk Bar (bound at Foo.hs:4:28)
In the expression: _
In an equation for ‘foom’: foom = _
In the instance declaration for ‘Foo Bar’
컴파일러가 클래스 유형 변수를 이미 인스턴스화하려는 구체 유형 Bar
채우는 방법에 유의하십시오. 이렇게하면 클래스 문서에서 발견되는 다형성보다 훨씬 쉽게 서명을 이해할 수 있습니다. 특히 다중 매개 변수 유형 클래스와 같은 더 복잡한 메소드를 다루는 경우 더욱 그렇습니다.
하지만 Gronk
대체 Gronk
? 이 시점에서 Hayoo 에게 물어 보는 것이 좋습니다. 그러나 우리는 여전히 그것을 벗어날 수 있습니다 : 맹목적인 추측으로, 우리는 이것이 형식 생성자 일뿐만 아니라 단일 값 생성자라고 가정합니다. 즉, 어떤 식 으로든 Gronk a
값을 생성하는 함수로 사용될 수 있습니다. 그래서 우리는 시도
instance Foo Bar where
foom bar = _ Gronk
우리가 운이 좋다면, Gronk
은 실제로 값이고, 컴파일러는 이제
Found hole ‘_’
with type: (Int -> [(Int, b0)] -> Gronk b0) -> Gronk Bar
Where: ‘b0’ is an ambiguous type variable
좋습니다. 그게 추한 것입니다. 처음에는 Gronk
이 두 가지 논점을 가지고 있으므로 시도를 다듬을 수 있습니다.
instance Foo Bar where
foom bar = Gronk _ _
그리고 지금 이것은 꽤 분명합니다.
Found hole ‘_’ with type: [(Int, Bar)]
Relevant bindings include
bar :: Bar (bound at Bar.hs:14:29)
foom :: Bar -> Gronk Bar (bound at Foo.hs:15:24)
In the second argument of ‘Gronk’, namely ‘_’
In the expression: Gronk _ _
In an equation for ‘foom’: foom bar = Gronk _ _
예를 들어 bar
값을 해체하여 추가 진행할 수 있습니다 (구성 요소는 Relevant bindings
섹션에 유형과 함께 표시됨). 올바른 정의가 무엇인지 완전히 명확한 시점이 종종 있습니다. 사용 가능한 모든 인수와 유형이 지그 소 퍼즐과 같이 결합되어 있기 때문입니다. 또는 정의가 불가능 하고 왜 그런지 알 수 있습니다.
이 모든 것은 인터랙티브 편집이 가능한 편집기에서 가장 잘 작동합니다 (예 : haskell-mode를 사용하는 Emacs). 그런 다음 IDE에서 마우스 오버 값 쿼리와 마찬가지로 입력 된 구멍을 사용하여 해석 된 동적 명령형 언어를 사용할 수 있지만 모든 제한은 없습니다.