Я пытался реализовать семейство типов Ty
на бумаге Generi c Программирование всех видов , которое вычисляет тип Atom
. Сначала я попытался использовать семейство закрытых типов так же, как в статье:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module GenericK where
import Data.Kind
type Kind = Type
-- | TyVar represents type parameters that the data takes
data TyVar (zeta :: Kind) (k :: Kind) :: Type where
VZ :: TyVar (x -> xs) x
VS :: TyVar xs k -> TyVar (x -> xs) k
-- | Atom is similar to K1
data Atom (zeta :: Kind) (k :: Kind) :: Type where
Var :: TyVar zeta k -> Atom zeta k
Kon :: k -> Atom zeta k
(:@:) :: Atom zeta (l -> k) -> Atom zeta l -> Atom zeta k
--| Gamma is a context
data Gamma (zeta :: Kind) where
Eta :: Gamma Type
(:&:) :: k -> Gamma ks -> Gamma (k -> ks)
type family Ty zeta (alpha :: Gamma zeta) (t :: Atom zeta k) :: k where
Ty (k -> ks) (t :&: alpha) (Var VZ) = t
Ty (k -> ks) (t :&: alpha) (Var (VS v)) = Ty ks alpha (Var v)
Ty zeta alpha (Kon t) = t
Ty zeta alpha (f :@: x) = (Ty zeta alpha f) (Ty zeta alpha x)
Однако GH C пожаловался:
• Expected kind ‘Atom zeta k’,
but ‘f’ has kind ‘Atom zeta (k -> k)’
• In the third argument of ‘Ty’, namely ‘f’
In the type ‘(Ty zeta alpha f) (Ty zeta alpha x)’
In the type family declaration for ‘Ty’
Сообщение об ошибке не имеет особого смысла мне ясно, что f
должен иметь вид Atom zeta (l -> k)
, а x
должен иметь вид Atom zeta l
.
Так что я попытался использовать семейство открытых типов, и это сработало:
type family Ty zeta (alpha :: Gamma zeta) (t :: Atom zeta k) :: k
type instance Ty (k -> ks) (t :&: alpha) (Var VZ) = t
type instance Ty (k -> ks) (t :&: alpha) (Var (VS v)) = Ty ks alpha (Var v)
type instance Ty zeta alpha (Kon t) = t
type instance Ty zeta alpha (f :@: x) = (Ty zeta alpha f) (Ty zeta alpha x)
Мне любопытно, почему семья закрытого типа не работала. Я думаю, это может быть связано с добрым полиморфизмом, но я не знаю, как работает проверка вида в GH C.