2015-03-12 11 views
6

Mam klasę dla kolejek, która pozwala instancji zdefiniować ograniczenia, które umieszcza na elementach. Na przykład, kolejka priorytet wymaga jego elementy będzie można zamówić:Czy mogę sparametryzować pusty typ ograniczenia?

{-# LANGUAGE MultiParamTypeClasses, ConstraintKinds, FunctionalDependencies #-} 

class Queue q c | q -> c where 
    empty :: q a 
    qpop :: c a => q a -> Maybe (a, q a) 
    qpush :: c a => a -> q a -> q a 

data PriorityQueue a = ... 

instance Queue PriorityQueue Ord where 
    ... 

Działa to zaklęcie: wewnątrz deklaracja instancja dla PriorityQueue mogę operować na elementach kolejki przy użyciu członków Ord takich jak (>).


ja utknąłem próbując określić kolejkę, która stawia żadnych wymagań na jej elementów:

newtype LIFO a = LIFO [a] 

instance Queue LIFO() where 
    empty = LIFO [] 
    qpop (LIFO []) = Nothing 
    qpop (LIFO (x:xs)) = Just (x, LIFO xs) 
    qpush x (LIFO xs) = LIFO $ x:xs 

zawodzi Ten, z następującym komunikatem o błędzie z GHC:

The second argument of `Queue' should have kind `* -> Constraint', 
    but `()' has kind `*' 
In the instance declaration for `Queue LIFO()' 

Ten komunikat o błędzie ma dla mnie sens. Eq akceptuje parametr typu (zazwyczaj piszemy Eq a => ...), podczas gdy () nie ma parametrów - jest to zwykły stary rodzaj niedopasowania.


miałem pęknięcie na napisanie funkcji typu, który ignoruje swój drugi argument, który pozwoliłby mi pisać instance Queue LIFO (Const()):

{-# LANGUAGE TypeFamilies, KindSignatures, PolyKinds #-} 

type family Const a b :: k -> k2 -> k 
type instance Const a b = a 

znajdę tę interakcję rodzin typu i polimorfizmu rodzaju bardzo piękne, więc byłem dość rozczarowany, kiedy to nie działa (naprawdę myślałem, że będzie!):

Expecting two more arguments to `a' 
The first argument of `Const' should have kind `*', 
    but `a' has kind `k0 -> k1 -> k0' 
In the type `a' 
In the type instance declaration for `Const' 

mam wrażenie ten ostatni przykład jest coś jak głupi błąd składni (jestem nowy, aby wpisać rodziny). Jak mogę napisać Constraint, który nie nakłada żadnych ograniczeń na jego argument?

+0

Spróbuj definiowania 'typ rodziny i mech (A :: k1) (B) :: k2 :: k1' następnie' Const (() :: Constraint) 'ma pożądany rodzaj, jednak nadal utknie. –

+0

@ J.Abrahamson Tak, wydaje się utknąć przy deklaracji "instancji": "Nielegalna aplikacja rodziny synonimów w instancji". Dlaczego moja pierwotna próba "Const" zawiodła? –

+0

Możesz być również zainteresowany zrobieniem tego właśnie z 'TypeFamilies'. http://www.skybluetrades.net/blog/posts/2015/03/08/constraint-kinds-associated-types.html – snak

Odpowiedz

7

To powinno działać:

class NoConstraint a where 
instance NoConstraint a where 

instance Queue LIFO NoConstraint where 
    ... 

Powyższe definiuje ograniczenia, które jest realizowane przez wszystkich typów. Jako takie, zobowiązania mogą być zawsze rozładowywane. Ponadto, ponieważ nie ma żadnych członków w tej klasie, powinien on mieć zerowy (lub prawie zerowy) koszt wykonania.

"Ograniczenie" (), którego próbujesz użyć, nie jest postrzegane jako puste ograniczenie ustawione przez GHC, ale jako typ jednostki () :: *. Powoduje to Const() :: k2 -> *, który wyzwala błąd rodzaju.

Jeśli nie chcesz używać niestandardowej klasy, możesz spróbować np. Const (Eq()) lub Const (Num Int), które mają odpowiedni rodzaj: k2 -> Constraint. Nie polecam tego jednak, ponieważ uważam, że jest mniej czytelny niż przy użyciu niestandardowej klasy.

(Wymaga to, aby umożliwić pewne rozszerzenia, jak Benjamin Hodgson zaznacza poniżej w komentarzu).

+3

Dzięki! W rzeczywistości, niezależnie od tego doszedłem do tego rozwiązania przed twoją odpowiedzią! Myślę, że warto podkreślić, że wymaga to 'FlexibleInstances' i działa najlepiej z włączonymi' PolyKinds' i 'KindSignatures' (możesz więc napisać' class NoConstraint (a :: k) '- inaczej GHC przyjmie' a :: * '). –

+0

Problem, który widzę tutaj, polega na tym, że ograniczenie "NoConstraint" "infekuje" wszystko przy użyciu kolejki. Czy byłoby możliwe obejście tego przy użyciu 'Const (NoConstraint())'? – dfeuer

+0

@dfeuer Jeśli ogólnie używasz kolejki, ograniczenie wygląda jak '(Queue qc, ca) => qa' co moim zdaniem nie jest zbyt uciążliwe –

Powiązane problemy