Sto studiando le caratteristiche della famiglia di tipi di Haskell e il calcolo del livello di tipo. Sembra che sia abbastanza facile da ottenere il polimorfismo parametrico a livello di tipo utilizzando PolyKinds
:Come creare una "classe tipo" in Haskell, o polimorfismo ad hoc a livello di tipo utilizzando famiglie di tipi
{-# 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
posso fare le cose come :kind! Bool == Bool
o :kind! Int == Int
o :kind! Z == Z
e :kind! (I Z (S Z)) == (I (S Z) (S (S Z)))
.
Tuttavia, desidero rendere il polimero ad-hoc type +
. In modo che sia limitato alle istanze che gli ho dato. I 2 esempi qui, sarebbero tipi di tipo NatK
e tipi di tipi IntK
.
ho provato rendendolo parametricamente polimorfa:
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)
Questo funziona, come posso fare :kind! (I (S Z) Z) :+ (I (S Z) Z)
.
Tuttavia, posso anche fare :kind! Bool :+ Bool
. E questo non ha alcun senso, ma lo consente come un semplice costruttore di tipi. Voglio creare una famiglia di tipi che non consenta tipi di questo tipo errati.
A questo punto sono perso. Ho provato le classi di tipo con un parametro type
. Ma quello non ha funzionato.
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)
Permette comunque :kind! Add Bool Bool
.
Questo ha qualcosa a che fare con l'estensione ConstraintKinds
, dove devo limitare lo :+
o Add
a qualche "classe gentile"?
Grazie! Questo è piuttosto interessante, ma potresti ampliare ciò che lo fa funzionare esattamente? Cioè, perché funziona? Sia per la soluzione open + closed, la soluzione KProxy e la soluzione TypeInType. – CMCDragonkai
Oh ma ho appena testato la tua prima soluzione, e permette comunque ': gentile! Aggiungi Bool Bool' risultante in 'Aggiungi Bool Bool :: *'. Speravo che questo diventasse un errore di tipo, invece di essere accettato !? – CMCDragonkai
Anche la tua seconda soluzione consente di aggiungere "Add Bool Bool". Non si presenta come un errore di tipo. – CMCDragonkai