Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does this mean by using 'type'

Tags:

haskell

I learned that a type synonym is a new name for an existing type. It can be used like

type MyChar = Char

But what does this usage mean like this?

class HasField a where
    type FieldType a :: *
like image 359
hl1020 Avatar asked Oct 31 '14 08:10

hl1020


2 Answers

That's an associated type family, an extension provided by GHC if you use the pragma

{-# LANGUAGE TypeFamilies #-}

or pass the parameter -XTypeFamilies to GHC or GHCi.

Basically, it declares a class such that each instance of the class can define individually what the type synonym means. For example:

data MyDataType = MyDataConstructor Int

instance HasField MyDataType where
    type FieldType MyDataType = Int
like image 61
Ørjan Johansen Avatar answered Sep 28 '22 03:09

Ørjan Johansen


All of this is a bit advanced so if you're just getting started with Haskell don't feel like you have to understand this right away.

That said, I'll add a simple example to Ørjan's answer, imagine we defined a class like this:

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

Now we can define instances for various types:

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

instance Unfoldable [] where
    fromList = id

instance Unfoldable Set where
    fromList = Set.fromList

But this has two weaknesses:

  • It doesn't work with monomorphic types: types that do not have a parameter for their element type. For example, ByteString and Text are monomorphic—their element type is hardcoded to Char8 and Char respectively.
  • It would be nice to have fromList :: Ord k = [(k, v)] -> Map k v, but that definition doesn't support it, because(k, v)is not a type parameter ofMap`.

So using TypeFamilies it's possible to improve it:

{-# 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

Look at the type of fromList :: Monoid m => [Element m] -> m. Basically, Element m is a synonym whose expansion is different for each differenct choice of m:

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

The other trick here is the use of ConstraintKinds to allow each class instance to require individualized constraints on the type variables (e.g., Ord k for Map). That's a topic for another day...

like image 21
Luis Casillas Avatar answered Sep 28 '22 05:09

Luis Casillas