読者です 読者をやめる 読者になる 読者になる

きくらげ観察日記

好きなことを、適当に。

型クラス自体を型として扱う

Haskell

ConstraintKinds拡張を使うと、型定義の=>の左辺にくる制約そのものを型として扱うことができるようになります。

{-# LANGUAGE ConstraintKinds #-}

-- ConstraintKinds拡張がなければこのような定義はできない
type MyShow t = Show t

-- typeで定義した制約を=>の左辺に書ける
myShow :: MyShow t => t -> String
myShow = show

このとき、=>の左辺にくる制約は、kindがGHC.Exts.Constraintであるような型として扱われます。

>>> :k Show
Show :: * -> Constraint

また、kindがConstraintであるような型c1, c2, ., cnに対して、タプル(c1, c2, .., cn)もConstraintとして扱われます。

-- ConstraintのタプルもConstraint
type ShowAndRead t = (Show t, Read t)

id' :: ShowAndRead t => t -> t
id' t = read $ show t

さらに、Constraintは型として扱われるため、他の型やクラスの型引数として扱うこともできます。

import GHC.Exts (Constraint)

data F (cls :: * -> Constraint) (a :: *)
  = F (forall t. cls t => t -> a)

hoge :: F Show String
hoge = F show