Apa itu sistem tipe?

50

Latar Belakang

Saya merancang bahasa, sebagai proyek sampingan. Saya memiliki assembler yang berfungsi, analisa statis, dan mesin virtual untuk itu. Karena saya sudah dapat mengkompilasi dan menjalankan program non-sepele menggunakan infrastruktur yang saya bangun, saya berpikir untuk memberikan presentasi di universitas saya.

Selama pembicaraan saya, saya menyebutkan bahwa VM menyediakan sistem tipe, ditanya "Untuk apa sistem tipe Anda? ". Setelah menjawab saya ditertawakan oleh orang yang mengajukan pertanyaan.

Jadi, meskipun saya hampir pasti akan kehilangan reputasi karena mengajukan pertanyaan ini, saya beralih ke Programmer.

Pemahaman saya

Seperti yang saya pahami, sistem tipe digunakan untuk memberikan lapisan informasi tambahan tentang entitas dalam suatu program, sehingga runtime, atau kompiler, atau bagian mesin lainnya, tahu apa yang harus dilakukan dengan rangkaian bit yang beroperasi. Mereka juga membantu mempertahankan kontrak - kompiler (atau penganalisa kode, atau runtime, atau program lain) dapat memverifikasi bahwa pada titik tertentu program beroperasi pada nilai-nilai yang diharapkan programmer untuk beroperasi.

Jenis juga dapat digunakan untuk memberikan informasi kepada programmer manusia tersebut. Misalnya, saya menemukan deklarasi ini:

function sqrt(double n) -> double;

lebih bermanfaat dari yang ini

sqrt(n)

Yang pertama memberikan banyak informasi: bahwa sqrtpengidentifikasi adalah fungsi, mengambil satu doublesebagai input, dan menghasilkan yang lain doublesebagai output. Yang terakhir memberitahu Anda bahwa itu mungkin fungsi yang mengambil parameter tunggal.

Jawabanku

Jadi, setelah ditanya, "Untuk apa sistem tipe Anda?" Saya menjawab sebagai berikut:

Sistem tipe bersifat dinamis (tipe ditugaskan ke nilai, bukan ke variabel yang menahannya), tetapi kuat tanpa aturan paksaan yang mengejutkan (Anda tidak dapat menambahkan string ke integer karena mereka mewakili tipe yang tidak kompatibel, tetapi Anda dapat menambahkan integer ke angka floating point) .

Sistem tipe digunakan oleh VM untuk memastikan bahwa operan untuk instruksi adalah valid; dan dapat digunakan oleh programmer untuk memastikan bahwa parameter yang diteruskan ke fungsinya valid (yaitu tipe yang benar).
Sistem tipe mendukung subtyping dan multiple inheritance (kedua fitur tersedia untuk programmer), dan tipe dipertimbangkan ketika pengiriman dinamis metode pada objek digunakan - VM menggunakan tipe untuk memeriksa dengan fungsi apa pesan yang diberikan diimplementasikan untuk tipe yang diberikan.

Pertanyaan tindak lanjut adalah "Dan bagaimana jenis ditugaskan ke nilai?". Jadi saya menjelaskan bahwa semua nilai dikotakkan, dan memiliki pointer yang menunjuk ke struktur definisi tipe yang memberikan informasi tentang nama tipe, pesan apa yang ditanggapi, dan tipe apa yang diwarisi darinya.

Setelah itu, saya ditertawakan, dan jawaban saya ditolak dengan komentar "Itu bukan sistem huruf yang nyata.".

Jadi - jika apa yang saya jelaskan tidak memenuhi syarat sebagai "sistem huruf nyata", apa yang akan terjadi? Apakah orang itu benar bahwa apa yang saya berikan tidak dapat dianggap sebagai sistem huruf?

Mael
sumber
19
Ketika orang berbicara tentang sistem ketik, mereka biasanya berbicara tentang pengetikan statis. Mengetik dinamis tidak terlalu menarik bagi orang-orang yang peduli pada sistem tipe karena hampir tidak ada jaminan apa pun. Misalnya, nilai apa yang dapat disimpan variabel x? Apa pun.
Doval
7
Saya ingin tahu apa yang mereka katakan untuk membela / menjelaskan reaksi mereka.
Newtopian
18
Pengetikan dinamis @Doval dapat menjamin Anda tidak memasuki kondisi tidak masuk akal dengan melakukan sesuatu seperti menambahkan 5 pada kucing Anda. Tentu, itu tidak akan mencegah Anda dari mencoba , tetapi setidaknya bisa menghentikannya dari benar-benar terjadi dan memberi Anda kesempatan untuk mencari tahu apa yang salah dan mengambil tindakan korektif, hal-hal yang tidak bisa dilakukan oleh bahasa yang benar-benar tanpa bahasa.
8bittree
10
Orang tersebut mempermasalahkan jawaban Anda untuk "Dan bagaimana jenis ditugaskan ke suatu nilai?". Mereka ingin mendengar tentang aturan mengetik, bukan diagram kotak-dan-pointer. Namun, tertawa benar-benar kasar.
Gardenhead
10
Orang yang tertawa kemungkinan besar adalah seorang fanatik untuk beberapa bahasa tertentu (keluarga) dengan sistem tipe yang kuat (Haskell tampaknya populer), dan akan mengolok-olok sesuatu yang kurang kuat (dan dengan demikian mainan) daripada itu, atau lebih kuat (dan dengan demikian tidak praktis), atau hanya berbeda. Terlibat dalam diskusi dengan orang-orang fanatik itu berbahaya dan sia-sia. Tertawa seperti itu sangat kasar sehingga menunjukkan masalah yang lebih dalam. Anda beruntung mereka tidak mulai berkhotbah ...
hyde

Jawaban:

30

Itu semua tampak seperti deskripsi yang bagus tentang sistem tipe apa yang disediakan. Dan implementasi Anda kedengarannya cukup masuk akal untuk apa yang dilakukannya.

Untuk beberapa bahasa, Anda tidak akan memerlukan informasi runtime karena bahasa Anda tidak melakukan pengiriman runtime (atau Anda melakukan pengiriman tunggal melalui vtables atau mekanisme lain, jadi tidak perlu informasi jenis). Untuk beberapa bahasa, hanya memiliki simbol / placeholder sudah cukup karena Anda hanya peduli tentang kesetaraan jenis, bukan nama atau warisannya.

Tergantung pada lingkungan Anda, orang tersebut mungkin menginginkan lebih banyak formalisme dalam sistem tipe Anda. Mereka ingin tahu apa yang bisa Anda buktikan dengannya, bukan apa yang bisa dilakukan oleh programmer . Sayangnya ini cukup umum di dunia akademis. Meskipun para akademisi melakukan hal-hal seperti itu karena cukup mudah untuk memiliki kekurangan dalam sistem tipe Anda yang memungkinkan hal-hal lolos dari kebenaran. Mungkin saja mereka melihat salah satunya.

Jika Anda memiliki pertanyaan lebih lanjut, Jenis dan Bahasa Pemrograman adalah buku kanonik tentang subjek tersebut dan dapat membantu Anda mempelajari beberapa ketelitian yang dibutuhkan oleh para akademisi, serta beberapa terminologi untuk membantu menggambarkan berbagai hal.

Telastyn
sumber
3
"Tergantung pada lingkunganmu, orang itu mungkin menginginkan lebih banyak formalisme dalam sistem tipemu." Mungkin itu. Saya tidak berkonsentrasi pada apa yang bisa saya buktikan dengan sistem tipe, tetapi lebih memikirkannya sebagai alat. Terima kasih untuk rekomendasi buku!
Mael
1
@Mael Beberapa sistem tipe digunakan sebagai logika (lihat kerangka kerja logis ). jadi pada dasarnya tipe memberi formula dan program adalah bukti dari formula tersebut (misalnya tipe fungsi a -> bdapat dilihat sebagai b) , yaitu jika Anda memberi saya nilai tipe asaya bisa mendapatkan nilai tipe b). Namun agar ini konsisten bahasa harus total, dan dengan demikian non-Turing lengkap. Jadi semua sistem tipe kehidupan nyata benar-benar mendefinisikan logika yang tidak konsisten.
Bakuriu
20

Saya suka jawaban @ Telastyn terutama karena referensi untuk kepentingan akademis dalam formalisme.

Izinkan saya untuk menambah diskusi.

Apa itu sistem tipe?

Sistem tipe adalah mekanisme untuk mendefinisikan, mendeteksi, dan mencegah status program ilegal. Ia bekerja dengan mendefinisikan dan menerapkan kendala. Definisi kendala adalah tipe , dan, aplikasi kendala adalah penggunaan tipe , misalnya dalam deklarasi variabel.

Jenis definisi biasanya mendukung operator komposisi (misalnya berbagai bentuk konjungsi, seperti dalam struktur, subkelas, dan, disjungsi, seperti pada enum, serikat pekerja).

Kendala, penggunaan jenis, kadang-kadang juga memungkinkan operator komposisi (misalnya setidaknya ini, tepat ini, ini atau itu, ini asalkan ada sesuatu yang lain memegang).

Jika sistem tipe tersedia dalam bahasa dan diterapkan pada waktu kompilasi menuju tujuan untuk dapat mengeluarkan kesalahan waktu kompilasi, itu adalah sistem tipe statis; ini mencegah banyak program ilegal dari kompilasi apalagi berjalan, karenanya mencegah negara program ilegal.

(Suatu sistem tipe statis menghentikan suatu program dari menjalankan apakah diketahui atau tidak (atau tidak dapat dipastikan) bahwa program tersebut akan mencapai kode tidak sehat yang dikeluhkannya. Sistem tipe statis mendeteksi jenis omong kosong tertentu (pelanggaran terhadap batasan yang dinyatakan) dan menilai program salah sebelum dijalankan.)

Jika sistem tipe diterapkan pada saat runtime, itu adalah sistem tipe dinamis yang mencegah status program ilegal: tetapi dengan menghentikan program pada pertengahan proses, alih-alih mencegahnya berjalan di tempat pertama.

Penawaran jenis sistem yang cukup umum adalah menyediakan fitur statis dan dinamis.

Erik Eidt
sumber
Saya tidak berpikir apa yang disebut sistem tipe hybrid sangat umum sekali. Bahasa apa yang Anda pikirkan?
Gardenhead
2
@gardenhead, kemampuan untuk downcast bukan fitur sistem tipe statis, oleh karena itu biasanya diperiksa saat runtime secara dinamis.
Erik Eidt
1
@gardenhead: sebagian besar bahasa yang diketik secara statis memungkinkan Anda untuk menunda pengetikan ke runtime, baik itu hanya dengan void *pointer C (sangat lemah), objek dinamis C #, atau GADT yang dikuantifikasi secara eksistensial Haskell (yang memberikan Anda jaminan yang lebih kuat daripada nilai yang diketik secara statis di sebagian besar lainnya. bahasa).
leftaroundabout
Benar, saya lupa tentang "casting". Tetapi casting hanyalah penopang untuk sistem tipe lemah.
Gardenhead
@gardenhead Serta bahasa statis menyediakan opsi dinamis, banyak bahasa dinamis menyediakan beberapa pengetikan statis. Misalnya, Dart, Python, dan Hack, semua memiliki mode atau alat untuk melakukan analisis statis berdasarkan konsep "pengetikan bertahap".
IMSoP
14

Oh man, saya senang mencoba menjawab pertanyaan ini sebaik mungkin. Saya harap saya dapat mengatur pikiran saya dengan benar.

Seperti @Doval sebutkan dan penanya tunjukkan (walaupun kasar), Anda tidak benar-benar memiliki sistem tipe. Anda memiliki sistem pemeriksaan dinamis menggunakan tag, yang secara umum jauh lebih lemah, dan juga jauh lebih menarik.

Pertanyaan "apa itu sistem tipe" bisa sangat filosofis, dan kita bisa mengisi buku dengan sudut pandang yang berbeda tentang masalah ini. Namun, karena ini adalah situs untuk pemrogram, saya akan mencoba menjaga jawaban saya sepraktis mungkin (dan sungguh, tipe sangat praktis dalam pemrograman, terlepas dari apa yang mungkin dipikirkan oleh beberapa orang).

Gambaran

Mari kita mulai dengan memahami apa jenis sistem yang baik untuk sistem, sebelum menyelam ke dasar yang lebih formal. Sistem tipe memaksakan struktur pada program kami . Mereka memberi tahu kami bagaimana kami dapat menyambungkan berbagai fungsi dan ekspresi secara bersamaan. Tanpa struktur, program tidak dapat dipertahankan dan sangat rumit, siap untuk menyebabkan kerusakan pada kesalahan sekecil apa pun dari programmer.

Program menulis dengan sistem tipe seperti mengemudi dengan hati-hati dalam kondisi mint - rem bekerja, pintu tertutup dengan aman, mesin diminyaki, dll. Program menulis tanpa sistem jenis seperti mengendarai sepeda motor tanpa helm dan dengan roda yang dibuat keluar dari spageti. Anda sama sekali tidak memiliki kendali atas Anda.

Sebagai landasan diskusi, katakanlah kita memiliki bahasa dengan ekspresi literal num[n]dan str[s]yang masing-masing mewakili n daneral s, dan fungsi primitif plusdan concat, dengan makna yang dimaksudkan. Jelas, Anda tidak ingin dapat menulis sesuatu seperti plus "hello" "world"atau concat 2 4. Tetapi bagaimana kita bisa mencegah ini? A priori , tidak ada metode untuk membedakan angka 2 dari string literal "dunia". Yang ingin kami katakan adalah bahwa ungkapan-ungkapan ini harus digunakan dalam konteks yang berbeda; mereka memiliki tipe yang berbeda.

Bahasa dan Jenis

Mari mundur sedikit: apa itu bahasa pemrograman? Secara umum, kita dapat membagi bahasa pemrograman menjadi dua lapisan: sintaks dan semantik. Ini juga disebut statika dan dinamika . Ternyata sistem tipe ini diperlukan untuk memediasi interaksi antara dua bagian ini.

Sintaksis

Program adalah pohon. Jangan tertipu oleh baris teks yang Anda tulis di komputer; ini hanya representasi yang bisa dibaca manusia dari suatu program. Program itu sendiri adalah Pohon Sintaks Abstrak . Sebagai contoh, dalam C kita dapat menulis:

int square(int x) { 
    return x * x;
 }

Itu adalah sintaks konkret untuk program (fragmen). Representasi pohon adalah:

     function square
     /     |       \
   int   int x    return
                     |
                   times
                  /    \
                 x      x

Sebuah bahasa pemrograman menyediakan tata bahasa mendefinisikan pohon valid bahwa bahasa (baik beton atau sintaks abstrak dapat digunakan). Ini biasanya dilakukan dengan menggunakan sesuatu seperti notasi BNF. Saya berasumsi Anda telah melakukan ini untuk bahasa yang Anda buat.

Semantik

OK, kita tahu apa itu program, tapi itu hanya struktur pohon statis. Agaknya, kami ingin program kami benar-benar menghitung sesuatu. Kami membutuhkan semantik.

Semantik bahasa pemrograman adalah bidang studi yang kaya. Secara umum, ada dua pendekatan: semantik denotasi dan semantik operasional . Semantik denotasional menggambarkan suatu program dengan memetakannya ke dalam beberapa struktur matematika yang mendasarinya (misalnya bilangan asli, fungsi kontinu, dll). yang memberikan makna bagi program kami. Semantik operasional, sebaliknya, mendefinisikan program dengan merinci bagaimana dijalankannya. Menurut pendapat saya, semantik operasional lebih intuitif untuk programmer (termasuk saya), jadi mari kita tetap dengan itu.

Saya tidak akan membahas cara mendefinisikan semantik operasional formal (detailnya sedikit terlibat), tetapi pada dasarnya, kami ingin aturan seperti berikut:

  1. num[n] adalah sebuah nilai
  2. str[s] adalah sebuah nilai
  3. Jika num[n1]dan num[n2]mengevaluasi ke integer n_1$ and $n_2$, thenplus (num [n1], num [n2]) `mengevaluasi ke integer $ n_1 + n_2 $.
  4. Jika str[s1]dan str[s2]mengevaluasi ke string s1 dan s2, maka concat(str[s1], str[s2])dievaluasi ke string s1s2.

Dll. Aturannya dalam praktik jauh lebih formal, tetapi Anda mendapatkan intinya. Namun, kami segera mengalami masalah. Apa yang terjadi ketika kita menulis yang berikut ini:

concat(num[5], str[hello])

Hm Ini cukup membingungkan. Kami belum menetapkan aturan di mana pun untuk cara menggabungkan angka dengan string. Kami dapat mencoba membuat aturan seperti itu, tetapi kami secara intuitif tahu bahwa operasi ini tidak ada artinya. Kami tidak ingin program ini valid. Dan dengan demikian kita dituntun ke jenis.

Jenis

Program adalah pohon sebagaimana didefinisikan oleh tata bahasa bahasa. Program diberi makna oleh aturan eksekusi. Tetapi beberapa program tidak dapat dijalankan; yaitu, beberapa program tidak ada artinya . Program-program ini salah ketik. Jadi, mengetik mencirikan program yang bermakna dalam suatu bahasa. Jika suatu program diketik dengan baik, kita dapat menjalankannya.

Mari kita beri beberapa contoh. Sekali lagi, seperti dengan aturan evaluasi, saya akan menyajikan aturan mengetik secara informal, tetapi mereka dapat dibuat ketat. Berikut ini beberapa aturan:

  1. Tanda bentuk num[n]memiliki tipe nat.
  2. Tanda bentuk str[s]memiliki tipe str.
  3. Jika ekspresi e1memiliki tipe natdan ekspresi e2memiliki tipe nat, maka ekspresi plus(e1, e2)memiliki tipe nat.
  4. Jika ekspresi e1memiliki tipe strdan ekspresi e2memiliki tipe str, maka ekspresi concat(e1, e2)memiliki tipe str.

Jadi, menurut aturan ini, ada plus(num[5], num[2])tipe is nat, tetapi kami tidak dapat menetapkan tipe plus(num[5], str["hello"]). Kami mengatakan sebuah program (atau ekspresi) diketik dengan baik jika kami dapat menetapkannya jenis apa pun, dan itu salah ketik. Sistem tipe adalah suara jika semua program yang diketik dengan baik dapat dieksekusi. Haskell adalah suara; C tidak.

Kesimpulan

Ada pandangan lain tentang tipe. Jenis-jenis tertentu berhubungan dengan logika intuitionistic, dan mereka juga dapat dilihat sebagai objek dalam teori kategori. Memahami koneksi-koneksi ini menarik, tetapi tidak penting jika seseorang hanya ingin menulis atau bahkan mendesain bahasa pemrograman. Namun, memahami tipe sebagai alat untuk mengendalikan formasi program sangat penting untuk desain bahasa pemrograman, dan pengembangan. Saya hanya menggores permukaan jenis apa yang bisa mengekspresikan. Saya harap Anda berpikir mereka cukup bermanfaat untuk dimasukkan ke dalam bahasa Anda.

kepala kebun
sumber
4
+1. Trik terbesar yang pernah dilakukan oleh para penggemar pengetikan dinamis adalah meyakinkan dunia bahwa Anda bisa memiliki "tipe" tanpa sistem tipe. :-)
ruakh
1
Karena Anda tidak dapat secara otomatis memverifikasi sesuatu yang menarik untuk program yang sewenang-wenang, setiap sistem jenis harus menyediakan operator pemain (atau yang setara secara moral), atau jika tidak mengorbankan kelengkapan Turing. Ini termasuk Haskell , tentu saja.
Kevin
1
@ Kevin Saya sangat sadar akan teorema Rice, tetapi itu tidak relevan seperti yang Anda pikirkan. Untuk memulainya, sebagian besar program tidak memerlukan rekursi yang tidak terbatas. Jika kami bekerja dalam bahasa yang hanya memiliki rekursi primitif, seperti Godel's System T, maka kami dapat memverifikasi properti menarik menggunakan sistem tipe, termasuk penghentian. Sebagian besar program di dunia nyata agak sederhana - saya tidak bisa memikirkan kapan terakhir kali saya benar-benar membutuhkan casting. Kelengkapan Turing dinilai terlalu tinggi.
Gardenhead
9
“Mengetik dinamis tidak benar-benar mengetik” bagi saya selalu seperti musisi klasik yang mengatakan “musik pop tidak benar-benar musik”, atau orang Injili mengatakan “Katolik bukan benar-benar Kristen”. Ya, sistem tipe statis sangat kuat dan menarik dan penting, dan pengetikan dinamis adalah sesuatu yang berbeda. Tetapi (seperti yang dijelaskan oleh jawaban lain) ada sejumlah hal berguna di luar sistem tipe statis yang secara tradisional disebut pengetikan, dan yang semuanya berbagi kesamaan penting. Mengapa harus bersikeras Mengetik Jenis Kami sebagai Satu-Satunya Mengetik?
Peter LeFanu Lumsdaine
5
@IMSoP: untuk sesuatu yang lebih pendek dari sebuah buku, esai Chris Smith Apa yang harus diketahui sebelum berdebat dengan sistem tipe sangat bagus, menjelaskan mengapa mengetik dinamis benar-benar sangat berbeda dengan mengetik statis.
Peter LeFanu Lumsdaine