J'étudie les caractéristiques de famille de types de Haskell, et le calcul de niveau type. Il semble qu'il est assez facile d'obtenir polymorphisme paramétrique au niveau de type en utilisant PolyKinds
:Comment créer une "classe kind" dans Haskell, ou un polymorphisme ad-hoc au niveau type en utilisant des familles de types
{-# LANGUAGE DataKinds, TypeFamilies, KindSignatures, GADTs, TypeOperators, UndecidableInstances, PolyKinds, MultiParamTypeClasses, FlexibleInstances #-}
data NatK = Z | S NatK
data IntK = I NatK NatK
infix 6 +
type family (x :: NatK) + (y :: NatK) :: NatK where
Z + y = y
(S x) + y = S (x + y)
-- here's a parametrically polymorphic (==) at the type-level
-- it also deals specifically with the I type of kind IntK
infix 4 ==
type family (a :: k) == (b :: k) :: Bool where
(I a1 a2) == (I b1 b2) = (a1 + b2) == (a2 + b1)
a == a = True
a == b = False
Je peux faire des choses comme :kind! Bool == Bool
ou :kind! Int == Int
ou :kind! Z == Z
et :kind! (I Z (S Z)) == (I (S Z) (S (S Z)))
.
Cependant, je veux faire type +
polymorphe ad-hoc. Alors que c'est contraint aux instances que je lui donne. Les 2 instances ici, seraient les types de type NatK
et les types de type IntK
.
J'ai d'abord essayé de faire ce paramétriquement polymorphes:
infix 6 :+
type family (x :: k) :+ (y :: k) :: k where
Z :+ y = y
(S x) :+ y = S (x :+ y)
(I x1 x2) :+ (I y1 y2) = I (x1 :+ y1) (x2 :+ y2)
Cela fonctionne, comme je peux le faire :kind! (I (S Z) Z) :+ (I (S Z) Z)
. Mais je peux aussi faire :kind! Bool :+ Bool
. Et cela n'a aucun sens, mais il le permet comme constructeur de type simple. Je veux créer une famille de types qui n'autorise pas de tels types errants.
À ce stade, je suis perdu. J'ai essayé des classes de type avec un paramètre type
. Mais cela n'a pas fonctionné.
class NumK (a :: k) (b :: k) where
type Add a b :: k
instance NumK (Z :: NatK) (b :: NatK) where
type Add Z b = b
instance NumK (S a :: NatK) (b :: NatK) where
type Add (S a) b = S (Add a b)
instance NumK (I a1 a2 :: IntK) (I b1 b2 :: IntK) where
type Add (I a1 a2) (I b1 b2) = I (Add a1 b1) (Add a2 b2)
Il permet toujours :kind! Add Bool Bool
.
Est-ce que cela a quelque chose à voir avec l'extension ConstraintKinds
, où je dois contraindre le :+
ou Add
à une certaine "classe aimable"?
Merci! C'est assez cool, mais pourriez-vous développer ce qui le fait fonctionner exactement? C'est, pourquoi ça marche? Pour votre solution ouverte + fermée, la solution KProxy et la solution TypeInType. – CMCDragonkai
Oh mais je viens de tester votre première solution, et cela permet toujours ': gentil! Ajoutez Bool Bool' résultant en 'Add Bool Bool :: *'. J'espérais que cela devienne une erreur de type, au lieu d'être accepté!? – CMCDragonkai
Aussi votre deuxième solution permet également «Ajouter Bool Bool». Il n'apparaît pas comme une erreur de type. – CMCDragonkai