Apakah jenis terhapus di Haskell?

13

Haskell memiliki gagasan tentang "fungsi generik" yang memiliki beberapa kemiripan yang jelas dengan common lisp — tidak memiliki pengalaman dengan Haskell atau dengan common lisp, saya mungkin sangat aproksipatif di sini. Ini berarti bahwa seseorang dapat mendefinisikan to_stringfasilitas generik untuk mendefinisikan representasi string untuk semua tipe. Tentu saja, fasilitas harus didefinisikan dalam kasus-kasus khusus tetapi ada to_stringfungsi yang tanda tangannya α → string.

Apakah jenis terhapus di Haskell, seperti di OCaml? Jika ya, bagaimana implementasi "fungsi generik" di Haskell berbeda dari yang umum, di mana jenisnya dinamis, dan dengan demikian tidak terhapus?

Saya mengerti bahwa detail implementasi spesifik untuk kompiler, tetapi mungkin ada ketentuan umum untuk banyak atau semua implementasi.

pengguna40989
sumber
5
Ingat Anda mungkin tidak dapat mendefinisikan fungsi tipe non-sepele a -> String. Anda akan lebih cenderung memiliki batasan tipe Show a => a -> String.
DJG

Jawaban:

16

Jawabannya sejauh ini menyesatkan.

Perlu dibuat perbedaan antara polimorfisme "parametrik" dan "ad-hoc overloading". Parametrik berarti "berperilaku seragam untuk semua jenis a", sedangkan "ad-hoc" - yang oleh Simon disebut polimorfik - mengubah implementasi berdasarkan jenisnya.

Contoh keduanya reverse :: [a] -> [a], yang parametrik, dan show :: Show a => a -> Stringyang "ad-hoc" kelebihan beban.

Jika Anda menginginkan lebih dari intuisi abstrak, saya pikir itu membantu untuk mempertimbangkan kelas kata kerja bahasa alami yang 'berfungsi' untuk semua objek, seperti "memiliki" atau "memikirkan" yang tidak menimbulkan kendala pada objek, tetapi " untuk membuka "membutuhkan apa yang kita bicarakan bisa dibuka. Saya dapat 'memikirkan pintu', dan 'membuka pintu', sementara tidak masuk akal misalnya 'membuka pohon'. Untuk mengambil contoh lebih jauh "membuka" adalah "polimorfik ad-hoc" sebagai "membuka jendela" dan "membuka tiket keluhan dengan layanan pelanggan" adalah dua hal yang sangat berbeda. Jika ini tampaknya dipaksakan - lupakan saja! Ini bekerja untuk saya.

Keduanya diselesaikan pada saat kompilasi, dan pada kenyataannya "dihapus". Modulo berbagai ekstensi GHC dan Template Haskell, dll Jenis yang sebenarnya terhapus pada waktu kompilasi dan tidak pernah diperiksa pada run-time.

Fungsi parametrik polimorfik berperilaku identik untuk semua jenis, sehingga hanya satu bagian kode yang perlu dihasilkan, sedangkan kompiler memutuskan pada waktu kompilasi versi fungsi "jenis-kelas" mana yang perlu dijalankan pada titik program tertentu. Ini juga mengapa ada pembatasan satu instance per tipe per tipe kelas dan work-around "newtype" yang sesuai ada.

Implementasinya dirinci dalam buku teks SPJ dan kertas Wadler dan Blotts pada kelas tipe .

Keris
sumber
Apakah Anda pikir saya harus menghapus jawaban saya?
Simon Bergot
Tidak, tidak apa-apa dengan peringatan Anda untuk tidak memukul kosakata yang tepat:)
Kris
Bisakah Anda memperluas sedikit tentang mengapa GHC dapat menghapus jenis? Apakah ini berkat pengetikan utama?
Simon Bergot
2
Secara umum pada saat runtime, baik fungsi polimorfik parametrik mungkin hanya ada satu kali dan memanggil fungsi polimorfik ad-hoc melalui beberapa metode pengiriman virtual atau semua kode dapat dihasilkan untuk setiap jenis secara terpisah dan panggilan yang terhubung secara statis. Entah implementasi benar dari sudut pandang bahasa (perhatikan, bahwa Haskell tidak memiliki jenis polimorfik; hal seperti itu hanya dapat dibuat dengan forallekstensi GHC ).
Jan Hudec
Apakah ada ekstensi GHC yang tidak memungkinkan jenis dihapus? Kelebihan beban statis dan tanpa tipe dependen penuh Saya tidak bisa memikirkan apa pun
Daniel Gratzer
1

peringatan: latar belakang saya di CS tidak terlalu kuat, jadi saya mungkin tidak selalu menggunakan kosa kata yang benar, dan saya mungkin salah pada beberapa poin. Bagaimanapun, inilah pemahaman saya:

Saya pikir Anda membingungkan generik dengan polimorfisme.

Tipe generik seperti List<Foo>digunakan untuk menggambarkan tipe yang menggunakan tipe lain sebagai parameter, dan memungkinkan pengecekan tipe yang lebih kaya.

Fungsi generik dalam haskell mungkin count:: List a -> Int. Ia menerima daftar jenis apa pun, dan mengembalikan jumlah elemen. Hanya ada satu implementasi.

Biasanya, ketika mendefinisikan Daftar, Anda tidak dapat mengasumsikan apa pun tentang T. Anda hanya dapat menyimpannya dan mengembalikannya.

to_stringFungsi Anda adalah fungsi polimorfik, yang artinya akan berperilaku berbeda dalam keadaan yang berbeda. Dalam haskell, ini dilakukan dengan kacamata ketik, yang berfungsi seperti kata sifat untuk jenis.

Anda memiliki Showtypeclass, yang mendefinisikan suatu show :: a -> Stringfungsi.

Ketika suatu tipe Foomengimplementasikan Showtypeclass, itu harus memberikan definisi show. Jenis ini kemudian dapat digunakan dalam fungsi yang membutuhkan Showkualifikasi (seperti pada Show a => a -> whatever). Haskell tidak dapat menghapus tipe, karena fungsi-fungsi itu harus menemukan implementasi showfungsi yang benar.

Simon Bergot
sumber
Secara umum, fungsi polimorfik disebut “fungsi generik” IIRC dan saya menggunakan kosakata yang sama (membingungkan). Jawaban Anda bermanfaat dan argumen akhir Anda cukup meyakinkan. .-)
user40989
“Hanya ada satu implementasi” —hanya implementasi yang masuk akal, tentu, tetapi ada banyak kemungkinan yang tak terhingga. Fungsi tipe a → b memiliki | b | ^ | a | kemungkinan implementasi (pertimbangkan jumlah fungsi tipe Bool → Bool), dan daftar tidak memiliki batas ukuran atas.
Jon Purdy