I was looking through the source code of Data.Has and trying to figure out how it works. I believe the following code is intended to allow someone to “Join” two values, say a :: A and b :: B into a new value that has the functionality of both a and b.
I particularly don’t understand what type means inside the class and instance declarations.
Also I don’t know what the ~ symbol means below.
Could someone explain the below code from Data.Has.TypeList works?
-- | 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)
typesyntax inside typeclass and instance declarations is a part ofTypeFamiliesextension. Type families can be thought as functions from types to types. There is a great detailed explanation of type and data families in the Haskell wiki (see the link).Applied to type classes, type families become associated types. In this regard they are very close to
FunctionalDependencies, that is, they allow unambigous instance resolution. The need for this is amply explained in the GHC manual.Type definitions in your example are very simple.
:::is another name for 2-tuple (a pair of values), andTyNilis isomorphic to unit type().I’ll try to read class and instance declaration so it will be clear what they mean.
These are type signatures of
(.++.)method in class declaration and instance declarations:Note that in each instance very abstract
a :++: btransforms to more concrete type. It is plainbin first case and more complexx ::: (y :++: b), itself written in terms of:++:.Such declaration of associated type is needed to tell the type system that there is some type (
a :++: bin this case) which is uniquely determined byaandbalone. That is, if typechecker knows that in certain expressionaandbtypes are equal to, say,IntandDouble, and:Append a b;Append Int Doublewith the associated type declared, say, astype Int :++: Double = String,then the typechecker will know that if he meet type
a :++: bit will know that in fact this type isString.As for
~, it is called ‘Lazy pattern match’. It is very clearly explained here.Feel free to ask if something is still not clear.