PolyKinds
PolyKindsを有効にすることでkindを多相にすることができる defaultでは、kindは*または->の2種類である
*は、いわば具体kindなので、そこへ*->*などを代入することはできない
例えば、data App f a = App (f a)という型は、
App :: (* -> *) -> * -> *と推論されるが、
App :: (ココ -> *) -> ココ -> *のココの部分は別に具体型じゃなくても矛盾は生じないはず
つまり、defaultでは無駄に制限が強い
そこで、PolyKindsを有効にすると、多相にできる箇所は多相で推論してくれる
App :: (k -> *) -> k -> *
kには、*でも*->*でも、*->*->*でも何でも取れるようになっている
安全な範囲で制限が緩まった感じmrsekut.icon
有効にする前後で、ghciの:kの結果が変わっている
簡単な例
PolyKindsを有効にする前では、
code:hs
{-# LANGUAGE DataKinds #-} data N (n :: *) = N -- data N n = N と同じ
type A1 = N Int -- ok
type A2 = N (Int -> String) -- ok
type A3 = N Maybe -- error
型引数nのkindは、無駄に*へと具体化されてしまうので、Maybeのような*->*な型は代入できない
有効にすると、
code:hs
-- {-# LANGUAGE DataKinds #-} 不要 {-# LANGUAGE PolyKinds #-} data P (n :: k) = P
type A1 = P Int -- ok
type A2 = P (Int -> String) -- ok
type A3 = P Maybe -- ok
使用例
実際の定義はもう少し複雑だがノリはこんなん
code:hs
data Proxy (t :: k) = Proxy
任意のkindの型を引数に取る幽霊型
もし、PolyKindsがなかったら*->*のレベルごとに定義しないといけない
code:hs
{-# LANGUAGE KindSignatures #-} data Proxy1 (a :: *) = Proxy1 -- Proxy1 Maybeはerrorになる
data Proxy2 (a :: * -> *) = Proxy2
data Proxy3 (a :: * -> * -> *) = Proxy3
..
purs
pursはv0.14.0からはいった
だから、dataやclassで型変数を用いた定義をしたい場合は記述方法が以前と異なる
pursuitの型表記が2021/7/4現在古いままになってる
classの場合はこんな感じになる
classの返り値をConstraintにしないといけないのはちょっと覚えづらい
型の文脈でのTypeみたいな感じかmrsekut.icon
code:purs(hs)
class Cons :: forall k. Symbol -> k -> Row k -> Row k -> Constraint
class Cons label a tail row | label a tail -> row, label row -> a tail
参考
わかりやすい