2017-12-18 90 views
9

Na przykład mam klasy typ:W Haskell, czy możliwe jest zapewnienie domyślnej implementacji dla częściowo zastosowanej klasy typu wieloparametrowego?

class MyClass a b c where 
    fun01 :: a -> b 
    fun02 :: a -> c 

    fun03 :: a -> b -> c ->() 
    fun04 :: a -> WhatEver 

chciałbym zapewnić realizację domyślny dla mojej, nazwijmy to BaseDataType który określa implementacje fun03 chodzi o to samo i fun01 i fun02. Wtedy mam coś takiego:

class MyClass BaseDataType b c where 
    fun03 = fun01 <$> fun02 ... 
    fun04 = fun02 ... 

I niż sfinalizować moje wystąpienie klasy i uniknąć cały kod szablonowe dla fun03 i fun04 bym po prostu dostarczyć fun01 i fun02 takiego:

instance MyClass BaseDataType Int Char where 
    fun01 = 1 
    fun02 = 'C' 

Czy jest możliwe rozszerzenie języka, które pozwala na takie zachowanie? Nie mogłem znaleźć niczego na ten temat.

Odpowiedz

10

Nie ma takiego przedłużenia, ale można osiągnąć tę funkcjonalność po prostu dzieląc swoją klasę na dwie klasy:

class MyClass1 a b c where 
    fun03 :: a -> b -> c ->() 
    fun04 :: a -> WhatEver 

class MyClass1 a b c => MyClass2 a b c where  
    fun01 :: a -> b 
    fun02 :: a -> c 

Następnie instancje będą działać tak, jak chcesz:

-- NB: need the MyClass2 constraint if you use `fun01` or `fun02` in the definitions 
-- This requires UndecidableInstances 
instance MyClass2 BaseDataType b c => MyClass1 BaseDataType b c where 
    fun03 = fun01 <$> fun02 ... 
    fun04 = fun02 ... 

instance MyClass2 BaseDataType Int Char where 
    fun01 = 1 
    fun02 = 'C' 

Użytkownicy twojej klasy nie są dotknięte; mogą nadal konsumować MyClass2, gdzie wcześniej używali MyClass i otrzymywali dokładnie tę samą funkcjonalność.


marginesie: oryginalna definicja MyClass i MyClass1 i MyClass2 nawet nie skompilować ze względu na kilka błędów typu niejednoznacznych (c nie jest wymieniony w rodzaju fun01, etc.) - Zakładam, że klasa ta była zdefiniowane tylko dla celów demonstracyjnych i nie próbowałem tego naprawiać.

4

Można użyć DefaultSignatures jak ten

class MyClass a b c where 
    fun01 :: a -> b 
    fun02 :: a -> c 

    fun03 :: a -> b -> c ->() 
    default fun03 :: (a ~ BaseDataType) => a -> b -> c ->() 
    fun03 = fun01 <$> fun02 ... 

    fun04 :: a -> WhatEver 
    default fun04 :: (a ~ BaseDataType) => a -> WhatEver 
    fun04 = fun02 ... 
+2

+1, ale nie liczyć to usuable dla PO, bo domyślnie jest _for all_ 'przypadki MyClass', nie tylko dla' MojaKlasa BaseDataType' specjalizacja. (W innych przypadkach domyślna implementacja spowoduje po prostu błąd typu niejasnego w celu wskazania, że ​​niestandardowe wystąpienie musi zostać zastąpione). – leftaroundabout