2012-03-03 15 views
6

Próbuję zdefiniować parę instancji klasy indukcyjnie. To znaczy:Ograniczenie typu "nie" Haskella

class Foo a b | a -> b where 
    foo :: a -> b 

instance (not?)Foo a => Bar a b 
    foo x = ... 

instance Foo a => Bar a b 
    foo x = ... 

Pierwsze instancje określają akcję podstawową, a sekundy rekurencyjnie wywołują foo. Czy jest jakiś sposób to zrobić? Dobrym przykładem może być spłaszczenie listy, gdzie w pierwszym przypadku jest to funkcja tożsamości, a w drugim rekursywna aplikacja konkat.

+10

Zauważ, że w Haskell nie można mieć pewności, że dany typ jest * nie * instancją klasy danego typu, ponieważ ktoś inny mógłby skompilować twój kod z własnym kodem dostarczającym instancję. –

Odpowiedz

5

Oto implementation of a flatten function, który działa z dowolnym poziomem zagnieżdżonej listy. Nie polecałbym jednak używania go - tutaj po prostu dla pokazania, jak osiągnąć coś takiego w haskell.

+5

Używanie IncoherentInstances to zaproszenie do kłopotów. – augustss

+1

@augustss, bardzo prawdziwe, stąd disclamer, który umieściłem na górze. Nie sądzę, że możliwe jest zaimplementowanie 'flatten' bez' IncoherentInstances' (co jest prawdopodobnie bardzo dobrym wskazaniem, że projektowanie programu bazującego na tej funkcji jest złym pomysłem). –

+1

@ is7s: Rozwiązanie tam nie może wyprowadzić typu spłaszczonej listy (musisz więc określić ją jako 'spłaszczyć [[3], [4]] :: [Int]'. Do tej pracy t potrzebujesz trzy rozszerzenia, które podałeś.Jest to opłacalna kompilacja. –

8

Nie można tego zrobić bezpośrednio, z bardzo prostego powodu - wybór instancji dotyczy tylko "głowy", tj. Części po =>. Nic, co umieścisz w kontekście - część przed => - może wpłynąć na wybraną instancję.

W przypadku prostych spraw często można uniknąć problemu w całości, na przykład gdy istnieje ograniczona liczba typów "podstawowych". Typowym przykładem będą listy typów, gdzie będziesz miał rekurencyjny przypadek dla Cons i podstawowy przypadek Nil i to wszystko.

W typowym przypadku zwykle potrzebna jest jakaś klasa typu "test warunkowy", która wybiera typ w zależności od tego, czy spełniony jest jakiś warunek, a następnie przekazuje rzeczywistą implementację klasie "pomocnika", która przyjmuje wartość wyniku warunkowego jako parametr i używa go do wybrania instancji.

+1

W jaki sposób zaimplementowałbyś ogólną listę spłaszczającą członka klasy? – Jonathan

+7

Cóż, najbardziej szczera odpowiedź brzmi, że nie zrobiłbym tego. Nie da się tego zrobić bez przełamania polimorficznych sygnałów wejściowych i nie jest to wystarczające, aby uzasadnić kłopot, moim zdaniem. To powiedziawszy, w przypadku list spłaszczających myślę, że można polegać na nakładających się instancjach, aby wybrać między rekurencją a przypadkiem bazowym. Czy używasz tutaj 'OverlappingInstances '? Prawdopodobnie będziesz tego potrzebować w taki czy inny sposób. –

+3

Po co chcesz ogólną funkcję spłaszczania list? To rzadko przydatne. – augustss

Powiązane problemy