Wnioskowanie typu w Golang / Haskell

9

Czytałem, że Go nie ma prawdziwego wnioskowania o typie w takim sensie, jak języki funkcjonalne, takie jak ML lub Haskell, ale nie byłem w stanie znaleźć prostego do zrozumienia porównania dwóch wersji. Czy ktoś mógłby wyjaśnić w podstawowych terminach, w jaki sposób wnioskowanie o typie w Go różni się od wnioskowania o typie w Haskell oraz zalety / wady każdego z nich?

a3onstorm
źródło

Odpowiedzi:

13

Zobacz tę odpowiedź StackOverflow dotyczącą wnioskowania o typie Go. Sam nie jestem zaznajomiony z Go, ale na podstawie tej odpowiedzi wydaje się, że jest to jednokierunkowa „dedukcja typu” (pożyczyć trochę teminologii w C ++). Oznacza to, że jeśli masz:

x := y + z

następnie typ xjest wydedukowany przez ustalenie typu y + z, co jest stosunkowo trywialną rzeczą dla kompilatora. Aby to zrobić, rodzaje yi zmuszą być z góry znane : można tego dokonać za pomocą adnotacji typu lub wywnioskować z przypisanych im literałów.


Natomiast większość języków funkcjonalnych ma wnioskowanie typu, które wykorzystuje wszystkie możliwe informacje w module (lub funkcji, jeśli algorytm wnioskowania jest lokalny), aby wyprowadzić typ zmiennych. Skomplikowane algorytmy wnioskowania (takie jak Hindley-Milner) często wiążą się z pewną formą unifikacji typów (trochę jak rozwiązywanie równań) za kulisami. Na przykład w Haskell, jeśli napiszesz:

let x = y + z

wtedy Haskell może wywnioskować ten typ nie tylko, xale także yi zpo prostu na podstawie tego, że wykonujesz na nich dodawanie. W tym przypadku:

x :: Num a => a
y :: Num a => a
z :: Num a => a

(Mała litera atutaj oznacza typ polimorficzny , często nazywany „ogólnymi” w innych językach, takich jak C ++. Num a =>Część jest ograniczeniem wskazującym, że aobsługa typów ma pewne pojęcie dodawania).

Oto bardziej interesujący przykład: kombinator stałoprzecinkowy, który umożliwia zdefiniowanie dowolnej funkcji rekurencyjnej:

let fix f = f (fix f)

Zauważ, że nigdzie nie podaliśmy typu fani nie podaliśmy typu fix, jednak kompilator Haskell może automatycznie stwierdzić, że:

f :: t -> t
fix :: (t -> t) -> t

To mówi, że:

  • Ten parametr fmusi być funkcją od dowolnego dowolnego typu tdo tego samego typu t.
  • fixto funkcja, która odbiera parametr typu t -> ti zwraca wynik typu t.
Rufflewind
źródło
4
bardziej dokładnie, Haskell można powiedzieć, że x, y, zsą takie same Numtyp Eric, ale nadal mogą być one Integers, Doubles, Ratio Integers ... Haskell jest skłonny do arbitralnego wyboru typów liczbowych, ale nie dla innych typeclasses.
John Dvorak,
7

Wnioskowanie o typach w Go jest niezwykle ograniczone i niezwykle proste. Działa tylko w jednym konstrukcie językowym (deklaracja zmiennej) i po prostu przyjmuje typ po prawej stronie i wykorzystuje go jako typ zmiennej po lewej stronie.

Wnioskowanie o typach w Haskell może być używane wszędzie, może służyć do wnioskowania o typach dla całego programu. Opiera się na unifikacji, co oznacza, że ​​(koncepcyjnie) wszystkie typy są wywnioskowane „na raz” i mogą one wpływać na siebie nawzajem: w Go informacje o typie mogą przepływać tylko z prawej strony deklaracji zmiennej do lewej- strona strony, nigdy w innym kierunku i nigdy poza deklaracją zmienną; w Haskell informacja o typie przepływa swobodnie we wszystkich kierunkach przez cały program.

Jednak system typów Haskell jest tak potężny, że wnioskowanie typu może faktycznie nie wywnioskować typu (a ściślej: należy wprowadzić ograniczenia, aby zawsze można było wywnioskować typ). System typów Go jest tak prosty (bez podtypów, polimorfizmu parametrycznego), a jego wnioskowanie jest tak ograniczone, że zawsze się udaje.

Jörg W Mittag
źródło
4
„w Haskell informacja o typie płynie swobodnie we wszystkich kierunkach przez cały program”: Uważam, że daje to bardzo dobrą intuicję. +1
Giorgio
Twierdzenia, które ta odpowiedź zawiera w ostatnim akapicie, są nieco mylące. Haskell nie ma podtypów. Ponadto parametryczny polimorfizm nie powoduje żadnego problemu dla kompletności wnioskowania o typie: Hindley-Milner na polimorficznym rachunku lambda zawsze znajduje najbardziej ogólny typ. Haskell może nie wywnioskować typów, ale dotyczy to wyrafinowanych funkcji systemu typów, takich jak GADT, w których przy naiwnym sformułowaniu nie istnieje żaden główny (tj. „Najlepszy wybór”) typ.
Edward Z. Yang,