Haskell Language
유형 가족
수색…
동의어 가족 유형
유형 동의어 패밀리는 유형 레벨 함수 일 뿐이며 매개 변수 유형을 결과 유형과 연관시킵니다. 이들은 3 개의 다른 다양성 들어온다.
폐쇄 형 - 동의어 계열
이것들은 통상적 인 값 - 레벨 하스켈 함수와 비슷하게 작동합니다 : 당신은 특정 타입을 다른 것들에 매핑하는 몇 가지 절을 지정합니다 :
{-# LANGUAGE TypeFamilies #-}
type family Vanquisher a where
Vanquisher Rock = Paper
Vanquisher Paper = Scissors
Vanquisher Scissors = Rock
data Rock=Rock; data Paper=Paper; data Scissors=Scissors
열린 타입 - 동의어 계열
이것은 typeclass 인스턴스와 비슷하게 작동합니다. 다른 모듈에 더 많은 절을 추가 할 수 있습니다.
type family DoubledSize w
type instance DoubledSize Word16 = Word32
type instance DoubledSize Word32 = Word64
-- Other instances might appear in other modules, but two instances cannot overlap
-- in a way that would produce different results.
클래스 관련 유형 동의어
개방형 패밀리는 실제 클래스와 결합 될 수도 있습니다. 이것은 연관된 데이터 패밀리 와 마찬가지로 일부 클래스 메소드가 추가 헬퍼 객체를 필요로하고 이러한 헬퍼 객체 가 다른 인스턴스에 대해 다를 수 있지만 공유 될 수도있는 경우에 일반적으로 수행됩니다. 좋은 예가 VectorSpace
클래스입니다 .
class VectorSpace v where
type Scalar v :: *
(*^) :: Scalar v -> v -> v
instance VectorSpace Double where
type Scalar Double = Double
μ *^ n = μ * n
instance VectorSpace (Double,Double) where
type Scalar (Double,Double) = Double
μ *^ (n,m) = (μ*n, μ*m)
instance VectorSpace (Complex Double) where
type Scalar (Complex Double) = Complex Double
μ *^ n = μ*n
처음 두 인스턴스에서 Scalar
의 구현이 어떻게 동일한 지 확인하십시오. 이것은 연관된 데이터 패밀리에서는 가능하지 않습니다. 데이터 패밀리는 주사 형 이고, 형 동의어 패밀리는 그렇지 않습니다.
비 주입성은 위와 같은 가능성을 열어 주지만, 타입 유추를 더욱 어렵게 만듭니다. 예를 들어, 다음은 typecheck되지 않습니다 :
class Foo a where
type Bar a :: *
bar :: a -> Bar a
instance Foo Int where
type Bar Int = String
bar = show
instance Foo Double where
type Bar Double = Bool
bar = (>0)
main = putStrLn (bar 1)
이 경우, bar
대한 인수는 그 자체가 다형 Num
Literal이므로, 컴파일러는 어떤 인스턴스를 사용할 지 알 수 없습니다. 그리고 타입 함수 Bar
는 "inverse direction"으로 해석 될 수 없습니다. 왜냐하면 그것은 injective † 가 아니기 때문에 invertible이 아니기 때문입니다 ( Bar a = String
가진 하나 이상의 타입이있을 수 있습니다).
† 이 두 인스턴스 만 있으면 실제로 주입식이지만 컴파일러는 나중에 다른 인스턴스를 추가하지 않아 작동을 중단한다는 것을 알 수 없습니다.
데이터 유형 패밀리
데이터 패밀리는 유형 인수를 기반으로 다른 구현을 갖는 데이터 유형을 작성하는 데 사용될 수 있습니다.
독립형 데이터 제품군
{-# LANGUAGE TypeFamilies #-}
data family List a
data instance List Char = Nil | Cons Char (List Char)
data instance List () = UnitList Int
위의 선언에서 Nil :: List Char
및 UnitList :: Int -> List ()
관련 데이터 제품군
데이터 패밀리는 typeclasses와 연관 될 수 있습니다. 이것은 일반적으로 일반적인 typeclass 메소드에 필요하지만 구체적인 인스턴스에 따라 다른 정보를 포함해야하는 "도우미 객체"가있는 유형에 유용합니다. 예를 들어, 목록의 색인 위치는 하나의 숫자 만 필요로하는 반면 트리에서는 각 노드의 경로를 나타내는 숫자가 필요합니다.
class Container f where
data Location f
get :: Location f -> f a -> Maybe a
instance Container [] where
data Location [] = ListLoc Int
get (ListLoc i) xs
| i < length xs = Just $ xs!!i
| otherwise = Nothing
instance Container Tree where
data Location Tree = ThisNode | NodePath Int (Location Tree)
get ThisNode (Node x _) = Just x
get (NodePath i path) (Node _ sfo) = get path =<< get i sfo
분사율
유형 가족은 반드시 주입식 일 필요는 없습니다. 따라서 응용 프로그램에서 매개 변수를 유추 할 수 없습니다. 예를 들어, servant
에서 주어진 유형이 Server a
경우 유형 a
추론 할 수 없습니다. 이 문제를 해결하기 위해 Proxy
를 사용할 수 있습니다. 예를 들어, servant
에서 serve
함수는 유형 ... Proxy a -> Server a -> ...
우리는 추론 할 수 a
에서 Proxy a
하기 때문에 Proxy
에 의해 정의 된 data
단사이다.