Studiuję cechy rodziny typów Haskella i obliczenia typu. Wydaje się to dość łatwo dostać się polimorfizm parametryczny na poziomie typu używając PolyKinds
:Jak stworzyć "klasę rodzajową" w Haskell lub polimorfizm ad-hoc na poziomie typu za pomocą rodzin typu
{-# 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
mogę robić takie rzeczy jak :kind! Bool == Bool
lub :kind! Int == Int
lub :kind! Z == Z
i :kind! (I Z (S Z)) == (I (S Z) (S (S Z)))
.
Jednak chcę utworzyć polimorficzny ad-hoc type +
. Tak więc jest ograniczony do instancji, które mu podaję. 2 wystąpienia tutaj byłyby rodzajami NatK
i rodzajami IntK
.
raz pierwszy spróbował co parametrycznie polimorficzny:
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)
To działa, jak mogę zrobić :kind! (I (S Z) Z) :+ (I (S Z) Z)
.
Mogę również wykonać: :kind! Bool :+ Bool
. I to nie ma sensu, ale pozwala na to jako prosty konstruktor typów. Chcę utworzyć rodzinę typów, która nie pozwala na takie błędne typy.
W tym momencie jestem zagubiony. Próbowałem klasy typów z parametrem type
. Ale to nie zadziałało.
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)
Nadal zezwala na :kind! Add Bool Bool
.
Czy to ma coś wspólnego z rozszerzeniem ConstraintKinds
, gdy trzeba ograniczyć :+
lub Add
do pewnego rodzaju „klasy”?
Dzięki! To jest całkiem fajne, ale czy możesz rozwinąć to, co dokładnie działa? To znaczy, dlaczego to działa? Zarówno dla otwartego, jak i zamkniętego rozwiązania, rozwiązania KProxy i rozwiązania TypeInType. – CMCDragonkai
Och, ale właśnie przetestowałem twoje pierwsze rozwiązanie i nadal pozwala na ': kind! Dodaj Bool Bool', co spowoduje 'Dodaj Bool Bool :: *'. Miałem nadzieję, że stanie się to błędem typu, zamiast zostać zaakceptowanym !? – CMCDragonkai
Również twoje drugie rozwiązanie pozwala również na 'Dodaj Bool Bool'. Nie pojawia się jako błąd typu. – CMCDragonkai