Jak dotąd odpowiedź jest myląca.
Należy wprowadzić rozróżnienie między polimorfizmem „parametrycznym” a „przeciążeniem ad hoc”. Parametryczny oznacza „zachowuje się jednakowo dla wszystkich typów a”, podczas gdy „ad-hoc” - co Simon nazywa polimorficznym - zmienia implementację w zależności od typu.
Przykładami obu są reverse :: [a] -> [a]
, które są parametryczne i show :: Show a => a -> String
które są „przeładowane ad-hoc”.
Jeśli chcesz bardziej abstrakcyjnej intuicji, myślę, że warto rozważyć klasy czasowników w języku naturalnym, które „działają” na wszystkie obiekty, takie jak „posiadać” lub „myśleć”, które nie stanowią ograniczeń dla obiektu, ale „ otwierać ”wymaga tego, o czym mówimy, można otworzyć. Mogę „myśleć o drzwiach” i „otwierać drzwi”, podczas gdy nie ma sensu np. „Otwierać drzewa”. Idąc dalej za przykładem „otwarcie” to „polimorficzne ad-hoc” jako „otwarcie okna” i „otwarcie biletu reklamacyjnego z obsługą klienta” to dwie bardzo różne rzeczy. Jeśli wydaje się to wymuszone - zapomnij! Mi to pasuje.
Oba są jednak rozwiązywane w czasie kompilacji i w rzeczywistości „kasowane”. Modulo różne rozszerzenia GHC i szablon Haskell itp. W rzeczywistości typy są kasowane podczas kompilacji i nigdy nie są sprawdzane w czasie wykonywania.
Funkcje parametrycznie polimorficzne zachowują się identycznie dla wszystkich typów, więc należy wygenerować tylko jeden fragment kodu, podczas gdy kompilator decyduje w czasie kompilacji, która wersja funkcji „klasy” powinna być uruchomiona w danym punkcie programu. Z tego powodu istnieje ograniczenie jednej instancji dla typu dla każdej klasy typu i odpowiedniego obejścia „nowego typu”.
Implementacja została szczegółowo opisana w podręczniku SPJ oraz papierze Wadlera i Blotta na temat klas typów .
a -> String
. Bardziej prawdopodobne jest ograniczenie typu, na przykładShow a => a -> String
.