2012-08-03 4 views
6

나는 소스 코드 Data.Has을보고 어떻게 작동하는지 알아 내려고했습니다. 다음 코드는 누군가가 "a :: A"과 "b :: B"이라는 두 값을 "a"과 "b"의 기능을 가진 새로운 값으로 "결합"할 수 있도록하기위한 것입니다.클래스 선언과 인스턴스 선언에 유형 키워드

특히 나는 type이 클래스 및 인스턴스 선언 내부에서 무엇을 의미하는지 이해하지 못합니다.

또한 ~의 의미는 무엇입니까?

누군가 아래의 코드를 Data.Has.TypeList에서 설명 할 수 있습니까? typeclass 및 인스턴스 선언 내부

-- | Provides type-list functionality 

module Data.Has.TypeList where 

import Control.Applicative 
import Data.Monoid (Monoid (..)) 
import Test.QuickCheck (Arbitrary (..), CoArbitrary (..)) 
import Data.Typeable 
import Data.Data 
-- | Cons a type onto type-list. 
data a ::: b = a ::: b deriving (Show,Eq,Ord,Read,Bounded,Typeable,Data) 

-- | The empty type-list. 
data TyNil = TyNil deriving (Read,Typeable,Data) 

-- | Appends a type-list and another. 
class Append a b where 
    type a :++: b 
    (.++.) :: a -> b -> a :++: b 
infixr 5 :++: 

-- Implementation of Append 

instance Append TyNil b where 
    type TyNil :++: b = b 
    _ .++. b = b 

instance (Append y b) => Append (x ::: y) b where 
    type (x ::: y) :++: b = x ::: (y :++: b) 
    ~(x ::: y) .++. b = x ::: (y .++. b) 
+0

관련 유형 동의어라고합니다. 이러한 구조는 기능적 종속성과 유사하지만 관계 대신 형식 함수를 사용합니다. –

답변

7

typeTypeFamilies 구문 확장의 일부이다. 타입 패밀리는 타입에서 타입으로의 함수로 생각할 수 있습니다. 하스켈 위키의 유형과 데이터 계열에 대한 자세한 설명이 있습니다 (링크 참조).

유형 클래스에 적용하면 유형 계열은 연관 유형이됩니다. 이 점에서 그들은 FunctionalDependencies에 매우 가깝습니다. 즉, 명확한 인스턴스 해석을 허용합니다. 이것에 대한 필요성은 충분히 설명되어 있습니다 in the GHC manual.

예제의 유형 정의는 매우 간단합니다. :::은 2-tuple (값 쌍)의 또 다른 이름이고 TyNil은 단위 유형 ()과 동형입니다.

클래스 및 인스턴스 선언을 읽으려고하면 의미를 명확히 알 수 있습니다. 종류 및 ab의 값을 취하고 형 a :++: b 값을 산출 연관된 유형 a :++: b 한 방법으로 기능 (.++.)Append a b typeclass

class Append a b where 
    type a :++: b 
    (.++.) :: a -> b -> a :++: b 
infixr 5 :++: 

선언 다중 매개. 또한 우선 오른쪽 연관 될 (.++.) 설정 5.

instance Append TyNil b where 
    type TyNil :++: b = b 
    _ .++. b = b 

a :++: b 관련된 고정 된 제 파라미터 (TyNil) 임의의 두 번째 매개 변수 (b)로 Append a b의 인스턴스를 선언 (투입 이 경우는 TyNil :++: b)은 b과 같다고 선언됩니다. (나는 어떤 방법을 설명하지 않을 것이고, 그것은 상당히 명확하다).

instance (Append y b) => Append (x ::: y) b where 
    type (x ::: y) :++: b = x ::: (y :++: b) 
    ~(x ::: y) .++. b = x ::: (y .++. b) 

선언 Append y b의 인스턴스가 이미 존재한다는 임의의 주어진 x y 및 임의의 제 파라미터에 대한 b 형태 x ::: y 먼저 Append a b 매개 변수의 인스턴스를 선언. 연관된 유형 a :++: b (여기에서 (x ::: y) :++: b, 분명히)은 x ::: (y :++: b)과 같다고 선언됩니다.메소드 정의도 여기에서 명확합니다 : 값 쌍과 다른 값을 취하여 첫 번째 요소가 첫 번째 인수와 동일하고 두 번째 요소가 두 번째 인수와 결합 된 첫 번째 인수의 두 번째 요소 인 .++. 메소드와 다른 쌍을 구성합니다. 우리는 .++. 때문에 Append y b 제약

로 사용할 수 있습니다 다음은 클래스 선언 및 인스턴스 선언에 (.++.) 방법의 유형 서명은 다음과 같습니다

(.++.) ::    a  -> b -> a :++: b 
(.++.) ::    TyNil -> b -> b 
(.++.) :: Append y b => x ::: y -> b -> x ::: (y :++: b) 

a :++: b 매우 추상적 각 인스턴스에서 더 구체적인 형식을 변환하는 것이 . 첫 번째 경우에는 보통 b이고 :++:으로 작성된 경우 더 복잡한 x ::: (y :++: b)입니다. 관련된 유형의

그러한 선언은 (이 경우 a :++: b) 어떤 유형이 있는지 의적 단독 ab 의해 결정 있는 타입 시스템에 알릴 필요가있다. typechecker 특정 표현에 ab 유형 IntDouble, 말, 동일한 것을 알고 있으며, 경우 즉, :

  1. 이 제약 Append a b있다;

는 다음 typechecker 그가 유형 a :++: b을 충족하는 경우 그 사실이 유형 String 것을 알고 것을 알게 될 것이다, type Int :++: Double = String로 말하자면, 선언 관련 유형의 타입 클래스 인스턴스 Append Int Double있다.

~의 경우 '지연 패턴 일치'라고합니다. 매우 명확하게 설명되어 있습니다 here.

아직 명확하지 않은지 언제든지 물어보십시오.

관련 문제