HaskellのType Families

型の族

this presentation in english

Github repository

Created by Dennis / @cdepillabout

intro

  • Haskellの初心者
  • type familiesって聞いたことあるけど何なのか分からなかった
  • このLTを機会に、型の族を調べて簡単に説明したい
  • Haskellのコードで型族を見る機会があった際に、「あ!これはあのプレゼンテーションで聞いたぞ!」と思っていただけるような内容にしたい

予備知識

型クラス(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が出力される
        print $ plus (5.0 :: Double) 6.0 -- 11.0が出力される

型クラスAdd aの宣言

インスタンス宣言

使い方

型クラスAddのaが変数みたいなもので、
インスタンス宣言でIntegerという値が入る。
Add Integerのインスタンスのプラス関数が下記の型になる
plus :: Integer -> Integer -> Integer

問題

どう書けばいい?

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

さっきのとちょっと変えた。
Addのインスタンスに2つの型を渡している。
こういうインスタンスを書きたいとき、
型クラスのplusメンバをどういうふうに書けばいい?

plus関数の型が書けない。
戻り値の型がaかbか?

インスタンスがAdd Integer Doubleのとき、
bの型で
plus :: a -> b -> b

Add Double Integerのとき、
aの型です
plus :: a -> b -> a

解決

型レベル関数?

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)
  • 前のスライドと変えたところを大きく表示した
  • 二行の追加とplusメンバの型
  • これが型の族 (type families)

まず、型クラスをみてみよう。
plusのSumTyの型ってどういう意味・・・?

こういう書き方のほうがわかりやすいでしょう。
SumTy a b = X。plusの戻り値の型がX。
インスタンス宣言ではXの値はDouble。

こういうふうに、型族が型レベル関数と呼ばれている

型族は実際にどこで使われている?

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

必要なLANGUAGE pragmas

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

型族と似ていて
同じような役割を果たしている

References

Thank You!