Jenis dalam Lisp dan Skema

10

Saya melihat sekarang bahwa Racket memiliki tipe. Sepintas sepertinya hampir identik dengan pengetikan Haskell. Tetapi apakah Lisp's CLOS mencakup beberapa jenis ruang Haskell yang tercakup? Membuat tipe Haskell yang sangat ketat dan objek dalam bahasa OO apa pun tampaknya agak mirip. Hanya saja saya sudah minum beberapa kool-Aid Haskell dan saya benar-benar paranoid bahwa jika saya pergi jalan Lisp, saya akan kacau karena mengetik dinamis.

pengguna2054900
sumber

Jawaban:

6

Sistem tipe CL lebih ekspresif daripada Haskell, misalnya, Anda dapat memiliki tipe (or (integer 1 10) (integer 20 30))untuk suatu nilai 1,2,...9,10,20,21,...,30.

Namun, kompiler Lisp tidak memaksa pemahaman mereka tentang keamanan mengetik di tenggorokan Anda, sehingga Anda dapat mengabaikan "catatan" mereka - dengan risiko Anda sendiri .

Ini berarti bahwa Anda dapat menulis Haskell di Lisp (dengan kata lain) dengan mendeklarasikan semua tipe nilai dan dengan hati-hati memastikan bahwa semua tipe yang diperlukan disimpulkan, tetapi kemudian lebih mudah menggunakan Haskell di tempat pertama.

Pada dasarnya, jika Anda ingin pengetikan statis yang kuat, gunakan Haskell atau OCaml, jika Anda ingin pengetikan dinamis yang kuat, gunakan Lisp. Jika Anda ingin mengetik statis lemah, gunakan C, jika Anda ingin mengetik dinamis lemah, gunakan Perl / Python. Setiap jalur memiliki kelebihan (dan fanatik) dan kelemahan (dan pencela), sehingga Anda akan mendapat manfaat dari mempelajari semuanya.

sds
sumber
19
Siapa pun yang menggunakan istilah seperti "paksa keselamatan tipe di tenggorokan Anda" tidak mengerti apa jenis keamanan itu atau mengapa itu berguna.
Mason Wheeler
11
@MasonWheeler: siapa pun yang mengambil kesimpulan dari satu frasa akan mendapati dirinya salah lebih sering daripada sebaliknya. Seperti, misalnya, dalam hal ini.
sds
4
Karena topiknya adalah bahasa, istilah "down your throat" sesuai dan cocok untuk pencitraan.
luser droog
1
@KChaloux: Maksud saya "ekspresif", seperti yang dijelaskan oleh contoh.
sds
4
Anda memiliki semuanya mundur. Pengetikan dinamis adalah kasus khusus pengetikan statis, di mana Anda memaksa pemrogram untuk menggunakan 1 jenis untuk semuanya. Saya dapat melakukan hal yang sama (secara lisan) di sebagian besar bahasa yang diketik secara statis dengan mendeklarasikan setiap variabel sebagai tipe Objectatau apa pun akar dari jenis pohon. Ini adalah kurang ekspresif, karena Anda kehilangan satu opsi mengatakan bahwa variabel-variabel tertentu hanya dapat berisi nilai-nilai tertentu.
Doval
5

Racket yang diketik sangat berbeda dari Haskell. Sistem tipe dalam Lisp dan Skema, dan tentu saja sistem tipe dalam ekosistem bahasa tradisional yang tidak diketik pada umumnya, memiliki tujuan mendasar bahwa sistem tipe lain tidak - beroperasi dengan kode untyped yang ada . Typed Racket misalnya memperkenalkan aturan pengetikan baru untuk mengakomodasi berbagai idiom Racket. Pertimbangkan fungsi ini:

(define (first some-list)
  (if (empty? some-list)
      #f
      (car some-list)))

Untuk daftar yang tidak kosong, ini mengembalikan elemen pertama. Untuk daftar kosong, ini mengembalikan false. Ini umum dalam bahasa yang tidak diketik; bahasa yang diketik akan menggunakan beberapa jenis pembungkus suka Maybeatau melemparkan kesalahan dalam kasing kosong. Jika kita ingin menambahkan tipe ke fungsi ini, tipe apa yang harus digunakan? Bukan [a] -> a(dalam notasi Haskell), karena dapat mengembalikan false. Ini juga tidak [a] -> Either a Boolean, karena (1) itu selalu mengembalikan false dalam kasus kosong, bukan boolean sewenang-wenang dan (2) jenis Entah akan membungkus elemen Leftdan salah Rightdan meminta Anda "membuka bungkus yang baik" untuk sampai ke elemen yang sebenarnya. Sebagai gantinya, nilai mengembalikan serikat yang benar- tidak ada pembungkus konstruktor, hanya mengembalikan satu jenis dalam beberapa kasus dan jenis lain dalam kasus lain. Di Typed Racket, ini diwakili dengan konstruktor tipe union:

(: first (All (A) (-> (Listof A) (U A #f))))
(define (first some-list)
  (if (empty? some-list)
      #f
      (car some-list)))

Tipe (U A #f)menyatakan fungsi dapat mengembalikan elemen daftar atau false tanpa Eithercontoh pembungkus . Pemeriksa tipe dapat menyimpulkan bahwa itu some-listadalah salah satu dari tipe (Pair A (Listof A))atau daftar kosong, dan selanjutnya menyimpulkan bahwa dalam dua cabang pernyataan if diketahui mana yang merupakan kasus . Pemeriksa tipe tahu bahwa dalam (car some-list)ekspresi, daftar harus memiliki tipe (Pair A (Listof A))karena kondisi if memastikannya. Ini disebut pengetikan kejadian dan dirancang untuk memudahkan transisi dari kode yang tidak diketik ke kode yang diketik.

Masalahnya adalah migrasi. Ada satu ton kode Racket yang tidak diketik di luar sana, dan Typed Racket tidak bisa memaksa Anda untuk meninggalkan semua pustaka untyped favorit Anda dan menghabiskan sebulan menambahkan jenis ke basis kode Anda jika Anda ingin menggunakannya. Masalah ini berlaku setiap kali Anda menambahkan tipe secara bertahap ke basis kode yang ada, lihat TypeScript dan Semua jenisnya untuk aplikasi javascript dari ide-ide ini.

Sistem tipe bertahap harus menyediakan alat untuk berurusan dengan idiom yang tidak diketik bersama dan berinteraksi dengan kode yang tidak diketik yang ada. Kalau tidak, akan sangat menyakitkan, lihat "Mengapa kita tidak lagi menggunakan Core.typed" untuk contoh Clojure.

Mendongkrak
sumber
1
Dalam ilmu ekonomi, ini dikenal sebagai Hukum Gresham : uang buruk mengusir kebaikan. Itu cenderung menemukan aplikasi dalam rekayasa juga. Ketika Anda memiliki dua subsistem yang secara teoritis setara dalam sistem Anda, terlalu sering yang lebih buruk akan menyebabkan terlalu banyak masalah untuk membuat yang lebih baik layak digunakan, seperti yang kita lihat di sini.
Mason Wheeler
"contoh merancang sistem tipe yang": kalimat ini tidak lengkap
coredump
@MasonWheeler Yang lebih buruk adalah, coba tebak, memeriksa tipe dinamis. Jadi, begitu Anda memperkenalkannya, tidak ada gunanya melakukan analisis statis?
coredump
1
@coredump - Pengetikan bertahap tidak sia-sia, kecuali jika Anda berinteraksi dengan kode yang tidak diketik dengan buruk. Tipe apa pun di TypeScript misalnya hanya memberi tahu typechecker untuk menyerah, pada dasarnya membuang manfaat dari sistem tipe karena dapat menyebabkan nilai yang buruk menyebar melalui sejumlah besar kode yang diperiksa secara statis. Racketed diketik menggunakan kontrak dan batas-batas modul untuk menghindari masalah ini.
Jack
1
@coredump Baca artikel Clojure. Memiliki pengetikan dinamis, terutama dengan semua kode pihak ketiga yang tidak memiliki tipe statis, benar-benar mengacaukan upaya mereka untuk meningkatkan basis kode dengan tipe statis.
Mason Wheeler