Ketik inferensi di Golang / Haskell

9

Saya telah membaca bahwa Go sebenarnya tidak memiliki inferensi tipe yang sebenarnya dalam arti bahwa bahasa fungsional seperti ML atau Haskell miliki, tetapi saya belum dapat menemukan perbandingan yang sederhana untuk memahami kedua versi. Bisakah seseorang menjelaskan secara mendasar bagaimana inferensi tipe di Go berbeda dari inferensi tipe di Haskell, dan pro / kontra dari masing-masing?

badai
sumber

Jawaban:

13

Lihat jawaban StackOverflow ini tentang inferensi tipe Go. Saya tidak terbiasa dengan Go sendiri tetapi berdasarkan jawaban ini sepertinya "cara mengurangi" satu arah (untuk meminjam beberapa teminologi C ++). Ini berarti bahwa jika Anda memiliki:

x := y + z

maka jenis xdisimpulkan dengan mencari tahu jenis y + z, yang merupakan hal yang relatif sepele untuk dilakukan untuk kompiler. Untuk melakukan ini, jenis ydan zperlu diketahui apriori : ini dapat dilakukan melalui anotasi jenis atau disimpulkan dari literal yang ditugaskan kepadanya.


Sebaliknya, sebagian besar bahasa fungsional memiliki tipe inferensi yang menggunakan semua informasi yang mungkin dalam modul (atau fungsi, jika algoritma inferensi lokal) untuk mendapatkan jenis variabel. Algoritma inferensi yang rumit (seperti Hindley-Milner) sering melibatkan beberapa bentuk penyatuan tipe (sedikit seperti memecahkan persamaan) di belakang layar. Misalnya, di Haskell, jika Anda menulis:

let x = y + z

maka Haskell dapat menyimpulkan jenis tidak hanya xtetapi juga ydan zhanya berdasarkan pada fakta bahwa Anda melakukan penambahan pada mereka. Pada kasus ini:

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

(Huruf kecil di asini menunjukkan tipe polimorfik , sering disebut "generik" dalam bahasa lain seperti C ++. Bagian Num a =>ini merupakan kendala untuk menunjukkan bahwa adukungan tipe memiliki beberapa gagasan tambahan.)

Berikut ini contoh yang lebih menarik: kombinator titik tetap yang memungkinkan setiap fungsi rekursif didefinisikan:

let fix f = f (fix f)

Perhatikan bahwa kami belum menentukan jenisnya f, kami juga tidak menentukan jenisnya fix, namun kompiler Haskell dapat secara otomatis mengetahui bahwa:

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

Ini mengatakan bahwa:

  • Parameter fharus berupa fungsi dari beberapa tipe arbitrer tke tipe yang sama t.
  • fixadalah fungsi yang menerima parameter tipe t -> tdan mengembalikan hasil tipe t.
Rufflewind
sumber
4
lebih tepatnya, Haskell dapat mengatakan bahwa x, y, zadalah sama Numjenis eric, tapi mereka masih bisa Integers, Doubles, Ratio Integers ... Haskell bersedia untuk membuat pilihan yang sewenang-wenang antara jenis numerik, tetapi tidak untuk typeclasses lainnya.
John Dvorak
7

Ketik inferensi di Go sangat terbatas dan sangat sederhana. Ini hanya berfungsi dalam satu konstruksi bahasa (deklarasi variabel) dan hanya mengambil jenis sisi kanan dan menggunakannya sebagai jenis untuk variabel di sisi kiri.

Jenis inferensi di Haskell dapat digunakan di mana-mana, dapat digunakan untuk menyimpulkan tipe-tipe untuk keseluruhan program. Ini didasarkan pada penyatuan, yang berarti bahwa (secara konseptual) semua jenis disimpulkan "sekaligus" dan mereka semua dapat saling mempengaruhi: di Go, informasi jenis hanya dapat mengalir dari sisi kanan deklarasi variabel ke kiri- sisi lain, tidak pernah ke arah lain dan tidak pernah di luar deklarasi variabel; di Haskell, ketik informasi mengalir dengan bebas ke segala arah melalui seluruh program.

Namun, sistem tipe Haskell sangat kuat sehingga inferensi tipe dapat benar-benar gagal menyimpulkan suatu tipe (atau lebih tepatnya: pembatasan harus diberlakukan sehingga suatu tipe selalu dapat disimpulkan). Sistem tipe Go sangat sederhana (tidak ada subtyping, tidak ada polimorfisme parametrik) dan kesimpulannya sangat terbatas sehingga selalu berhasil.

Jörg W Mittag
sumber
4
"di Haskell, ketik informasi mengalir dengan bebas ke segala arah melalui seluruh program": Saya menemukan ini memberikan intuisi yang sangat baik. +1
Giorgio
Klaim yang dibuat oleh jawaban ini pada paragraf terakhir agak menyesatkan. Haskell tidak memiliki subtipe. Lebih jauh, polimorfisme parametrik tidak menyebabkan masalah untuk kelengkapan tipe inferensi: Hindley-Milner pada kalkulus lambda polimorfik selalu menemukan tipe yang paling umum. Haskell dapat gagal menyimpulkan tipe, tetapi ini akan berada pada fitur sistem tipe canggih seperti GADTs, di mana, ketika diformulasikan secara naif, tidak ada tipe utama (yaitu, "pilihan terbaik") ada.
Edward Z. Yang