2013-04-12 18 views
15

Czytam artykuł o zależny wpisany programowania i natknąłem się na następujący cytat:Extensible Haskell Rodzaj Klasy

„[...] w przeciwieństwie do klas typu Haskell jest typ danych [...] jest zamknięte "w tym sensie, że nie można dodawać nowych typów do wszechświata bez rozszerzania typu danych.

Moje pytanie dla początkujących brzmi: w jakim sensie klasy typu Haskell to otwórz? Jak są rozszerzalne? Jakie są typowe teoretyczne konsekwencje posiadania tej właściwości (open vs closed)?

Dziękujemy!

Odpowiedz

9

Biorąc pod uwagę typ klasy jak:

class Monoid m where 
    mempty :: m 
    mappend :: m -> m -> m 

... to jest (w zasadzie) realizowane pod maską jako typ słownika:

data Monoid m = Monoid 
    { mempty :: m 
    , mappend :: m -> m -> m 
    } 

Przypadki takie jak:

instance Monoid [a] where 
    mempty = [] 
    mappend = (++) 

... przetłumaczyć na słowniki:

listIsAMonoid :: Monoid [a] 
listIsAMonoid = Monoid 
    { mempty = [] 
    , mappend = (++) 
    } 

... a kompilator konsultuje się z powyższym słownikiem za każdym razem, gdy używasz list w ich postaci jako Monoid.

To prowadzi nas do pytania:

w jakim sensie są zajęcia typu Haskell otwarte? Jak są rozszerzalne?

Są otwarte w tym samym sensie, że wartości polimorficzne są otwarte. Mamy pewne polimorficzny Typ danych:

data Monoid m = ... 

... i możemy instancję zmiennej m typu polimorficzny do dowolnego typu, gdzie możemy zapewnić odpowiednie wartości dla pól mempty i mappend.

+0

Interpretacja typu-klasy-słownika jest raczej specyficzna dla ghc. W specyfikacji haskell nie ma niczego, co by tego wymagało, a inne implementacje (np. Jhc) używają innego podejścia. –

+0

@JohnL Nadal jest przydatnym narzędziem mentalnym do zrozumienia zmysłu, w którym jest polimorficzny. –

12

Klasy typów są otwarte, ponieważ można dowolnie wpisać ich instancję. Tworząc klasę typu, określasz interfejs, ale nie typy, które do niego należą. Następnie w dowolnym kodzie, który zawiera definicję typu typograficznego, możesz utworzyć jego instancję typu, która dostarcza niezbędnych funkcji z interfejsu, używając składni instance TypeClass type of.

+1

Dziękuję za odpowiedź. Przedtem miałem intuicję interfejsu/implementacji. Moje pytanie dotyczyło raczej tego, czy można później rozszerzyć interfejs określony przez klasę typu, tj. Poprzez zdefiniowanie innego konstruktora dla tego typu danych poza zakresem początkowym? – AnaK

+0

Możesz rozszerzyć interfejs, definiując tylko nową klasę typów, jednak istnieje pojęcie dziedziczenia, które pozwala na jego rozszerzenie. Możesz użyć 'class (Interface BetterInterface) => BetterInterface type gdzie ...'. Porównaj w jaki sposób 'Monad' może być implementowany jako rozszerzenie' Functor'. – Adrian

+0

OK, rozumiem. Myślałem bardziej na linii typów ** otwartych **, że ich konstruktory mogą wyglądać na rozproszone, podczas gdy semantycznie zachowują się tak, jakby były zamknięte (zdefiniowane w jednym miejscu). – AnaK

2

Ralf Laemmel ma bardzo dobry video lectures on Channel9 na ten temat - bardzo zalecane.

+0

Dziękujemy za referencje! Nie zdawałem sobie sprawy z problemu ekspresji. – AnaK

3

Klasy typów są "otwarte", ponieważ zawsze można dodać do nich więcej typów "po fakcie", dodając więcej deklaracji instancji. Można to nawet zrobić w kodzie "klienta", który tylko wykorzystuje moduł zawierający klasę typu.

Najważniejsze jest to, że mogę napisać kod, który działa na wartościach z pewnym ograniczeniem klasy typów, a ten sam kod bez modyfikacji może być użyty dla typów, które nie istniały, gdy napisałem klasę typu.

Konkretne typy danych w Haskell są "zamknięte", ponieważ nie może się to zdarzyć. Jeśli napiszę kod, który działa na członkach określonego typu danych (nawet jeśli jest polimorficzny), to nie ma możliwości użycia tego kodu do działania na nowych rodzajach rzeczy, o których nie myślałem, chyba że jesteś w stanie zmodyfikować typ (która prawdopodobnie wymaga modyfikacji wszystkich miejsc, w których jest używana).