Haskell's Type Families

日本語

Github repository

Created by Dennis / @cdepillabout

intro

  • I am a Haskell beginner.
  • I've heard the term "type family", but I didn't know what it meant.
  • I will try to give a very simple explanation and motivation for type families.
  • You don't need to understand everything in this presentation, but hopefully next time you see type families being used, you can recall some of the ideas from here.

Prerequisites

type classes

class Add a where
    plus :: a -> a -> a

instance Add Integer where
    plus x y = x + y

instance Add Double where
    plus x y = x + y

main = do
        print $ plus (5 :: Integer) 6    -- 11 is printed
        print $ plus (5.0 :: Double) 6.0 -- 11.0 is printed

definition of typeclass Add a

instance declaration

how to use

The a from type class Add is like a variable,
it takes a variable Integer from the instance declaration.
The Add Integer instance's plus method will have the following type: plus :: Integer -> Integer -> Integer

The Problem

How can we write the following code?

class Add a b where
    plus :: a -> b -> ???

instance Add Integer Double where
    plus x y = fromIntegral x + y

instance Add Double Integer where
    plus x y = x + fromIntegral y

This is a little different from before.
We are now passing two types to Add.
When we want to write these instances of Add,
what should we write for the type of the plus function?

We can't write the type of plus.
Should the return type be a? b?

For the Add Integer Double instance,
it should be b:
plus :: a -> b -> b

For the Add Double Integer instance,
it should be a:
plus :: a -> b -> a

The Solution

Type-level functions

class Add a b where
    type SumTy a b = X
    plus :: a -> b -> SumTy a bX

instance Add Integer Double where
    type SumTy Integer Double = Double
    plus x y = fromIntegral x + y

instance Add Double Integer where
    type SumTy Double Integer = Double
    plus x y = x + fromIntegral y

instance (Num a) => Add a a where
    type SumTy a a = a
    plus x y = x + y

main = print $ plus (5 :: Integer) (6 :: Double)
  • The code changed from the previous slide has been highlighted.
  • Two lines have been added and plus's type is a little different.
  • This is a type family.

First, lets look at the type class.
What is the meaning of plus's SumTy?

Writing it like this should be a little easier to understand.
SumTy a b = X. The return type of plus is X.
In the instance declaration, the value of X is Double.

This is why they are called type-level functions.

Where are type families actually used?

Yesod!

class YesodAuth master where
  type AuthId master
  -- | Determine the ID associated with the set of credentials.
  getAuthId :: Creds master -> Maybe (AuthId master)

instance YesodAuth BrowserId where
  type AuthId BrowserId = Text
  getAuthId = Just . credsIdent

instance YesodAuth Auth2 where
  type AuthId BrowserId = String
  getAuthId = Just . credsIdent

Needed LANGUAGE pragmas for using type families

{-# LANGUAGE FlexibleContexts #-}

{-# LANGUAGE MultiParamTypeClasses #-}

{-# LANGUAGE TypeFamilies #-}

Functional Dependencies

class Add a b c | a b -> c where
    plus :: a -> b -> c

instance Add Integer Double Double where
    plus x y = fromIntegral x + y

instance Add Double Integer Double where
    plus x y = x + fromIntegral y

instance (Num a) => Add a a a where
    plus x y = x + y

main = print $ plus (5 :: Integer) (6 :: Double)

Similar to type families and
can be used in some of the same places.

References

Thank You!