2014-10-31 10 views
9

Ich habe gelernt, dass ein type Synonym ein neuer Name für einen vorhandenen Typ ist. Es kann verwendet werden wieWas bedeutet das mit 'type'

type MyChar = Char 

Aber was bedeutet diese Verwendung so?

class HasField a where 
    type FieldType a :: * 

Antwort

11

Das ist ein associated type family, eine Erweiterung von GHC zur Verfügung gestellt, wenn Sie die Pragma verwenden

{-# LANGUAGE TypeFamilies #-} 

oder übergeben Sie den Parameter -XTypeFamilies-GHC oder GHCi.

Grundsätzlich deklariert es eine Klasse, so dass jede Instanz der Klasse individuell definieren kann, was der Typ Synonym bedeutet. Zum Beispiel:

data MyDataType = MyDataConstructor Int 

instance HasField MyDataType where 
    type FieldType MyDataType = Int 
+0

Ich sehe jetzt und Danke!Ich denke, es ist vielleicht besser, den GHC-Benutzerhandbuch zu lesen, bevor Sie mit dem Lesen von Quellcode beginnen ... – hl1020

2

All dies ist ein bisschen so weit fortgeschritten, wenn Sie nur mit Haskell Sie beginnen nicht das Gefühl, wie Sie dies sofort verstehen haben.

Das heißt, werde ich ein einfaches Beispiel zu Ørjan Antwort hinzufügen, stellen wir eine Klasse wie folgt definiert:

-- | Class for types that can be constructed from a list of items. 
class Unfoldable t where 
    fromList :: [a] -> t a 

Jetzt können wir Instanzen für verschiedene Arten definieren:

import Data.Set (Set) 
import qualified Data.Set as Set 

instance Unfoldable [] where 
    fromList = id 

instance Unfoldable Set where 
    fromList = Set.fromList 

Aber dies hat zwei Schwächen:

  • Es ist nicht mit monomorphic funktioniert Typen: Typen, die keinen Parameter für ihren Elementtyp haben. Zum Beispiel sind ByteString und Text monomorph - ihr Elementtyp ist fest auf Char8 bzw. Char codiert.
  • Es wäre schön zu haben fromList :: Ord k = [(k, v)] -> Map k v, but that definition doesn't support it, because (k, v) is not a type parameter of Map`.

mit So TypeFamilies es möglich ist, um es zu verbessern:

{-# LANGUAGE TypeFamilies, ConstraintKinds #-} 

import Data.Monoid 
import Data.Set (Set) 
import qualified Data.Set as Set 
import Data.Map (Map) 
import qualified Data.Map as Map 
import Data.Text (Text, pack) 
import GHC.Exts (Constraint) 

class Monoid m => Unfoldable m where 
    type Element m :: * 
    type Constraint m :: GHC.Exts.Constraint 
    type Constraint m =() 

    fromList :: [Element m] -> m 

instance Unfoldable [a] where 
    type Element [a] = a 
    fromList as = as 

instance Ord a => Unfoldable (Set a) where 
    type Element (Set a) = a 
    type Constraint (Set a) = Ord a 
    fromList = Set.fromList 

instance Ord k => Unfoldable (Map k v) where 
    type Element (Map k v) = (k, v) 
    type Constraint (Map k v) = Ord k 
    fromList = Map.fromList 

instance Unfoldable Text where 
    type Element Text = Char 
    fromList = pack 

Blick auf die Art der fromList :: Monoid m => [Element m] -> m. Grundsätzlich Element m ist ein Synonym deren Erweiterung ist für jede differenct Wahl von m:

  • Element [a] := a
  • Element (Map k v) := (k ,v)
  • Element Text := Char

Der andere Trick ist die Verwendung von ConstraintKinds zu jedem erlauben Klasseninstanz, die individualisierte Einschränkungen für die Typvariablen erfordert (z. B. Ord k für Map). Das ist ein Thema für einen anderen Tag ...

+0

(1) Ich sehe, dass Sie den Typ "Constraint" definieren, aber Sie scheinen ihn nicht zu verwenden. Ich nehme an, du willst es als Einschränkung für 'fromList'? (2) Wenn Sie darauf bestehen, den widersprüchlichen Namen 'Constraint' zu verwenden, sollten' GHC.Exts' als 'qualifiziert' importiert werden, auch wenn dies beim Definieren der Instanzen passiert. –