Saya belajar pemrograman dalam ML (OCaml), dan sebelumnya saya bertanya tentang fungsi tipe ML'a -> 'b
. Sekarang saya sudah bereksperimen sedikit dengan fungsi tipe 'a list -> 'b list
. Ada beberapa contoh sederhana yang jelas:
let rec loop l = loop l
let return_empty l = []
let rec loop_if_not_empty = function [] -> []
| l -> loop_if_not_empty l
Apa yang saya tidak tahu adalah bagaimana membuat fungsi yang melakukan sesuatu selain mengembalikan daftar kosong atau loop (tanpa menggunakan fungsi pustaka). Bisakah ini dilakukan? Apakah ada cara untuk mengembalikan daftar yang tidak kosong?
Sunting: Ya, jika saya memiliki fungsi tipe 'a -> 'b
, maka saya bisa membuat yang lain, atau fungsi tipe 'a list -> 'b list
, tapi yang saya ingin tahu di sini adalah bagaimana membuat yang pertama.
programming-languages
typing
functional-programming
Gilles 'SANGAT berhenti menjadi jahat'
sumber
sumber
Jawaban:
Nah, sesuatu yang dikenal sebagai parametrik memberi tahu kita bahwa jika kita menganggap subset murni ML (yaitu, tidak ada rekursi tak terbatas,
ref
dan semua hal aneh), tidak ada cara untuk mendefinisikan fungsi dengan tipe ini selain yang mengembalikan yang kosong daftar.Ini semua dimulai dengan makalah Wadler “ Teorema gratis! ” Makalah ini, pada dasarnya, memberi tahu kita dua hal:
ref
dan semua hal aneh itu) memenuhi kondisi itu.Dari Parametricity Teorema kita tahu bahwa jika kita memiliki fungsi
f : 'a list -> 'b list
, maka untuk semua'a
,'b
,'c
,'d
dan untuk semua fungsig : 'a -> 'c
,h : 'b -> 'd
kita memiliki:(Catatan,
f
di sebelah kiri memiliki tipe'a list -> 'b list
danf
di sebelah kanan adalah'c list -> 'd list
.)Kita bebas memilih apa pun yang
g
kita suka, jadi mari'a = 'c
dang = id
. Sekarang karenamap id = id
(mudah dibuktikan dengan induksi pada definisimap
), kami memiliki:Sekarang biarkan
'b = 'd = bool
danh = not
. Mari kita asumsikan untuk beberapazs : bool list
hal itu terjadif zs ≠ [] : bool list
. Hal ini jelas bahwamap not ∘ f = f
tidak tidak tahan, karenaJika elemen pertama dari daftar di sebelah kanan adalah
true
, maka di sebelah kiri elemen pertama adalahfalse
dan sebaliknya!Ini artinya, anggapan kita salah dan
f zs = []
. Sudahkah kita selesai? Tidak.Kami berasumsi bahwa
'b
adalahbool
. Kami telah menunjukkan bahwa ketikaf
dipanggil dengan tipef : 'a list -> bool list
untuk apa pun'a
,f
harus selalu mengembalikan daftar kosong. Mungkinkah ketika kita memanggilf
karenaf : 'a list -> unit list
mengembalikan sesuatu yang berbeda? Intuisi kita memberi tahu kita bahwa ini omong kosong: kita tidak bisa menulis dalam ML murni suatu fungsi yang selalu mengembalikan daftar kosong ketika kita ingin memberi kita daftar boolean dan mungkin mengembalikan daftar yang tidak kosong kalau tidak! Tapi ini bukan bukti.Apa yang ingin kita katakan adalah bahwa
f
adalah seragam : jika selalu mengembalikan daftar kosong untukbool list
, maka harus mengembalikan daftar kosong untukunit list
dan, secara umum, setiap'a list
. Inilah tepatnya poin kedua dalam daftar peluru di awal jawaban saya.Makalah ini memberitahu kita bahwa di ML
f
harus mengambil terkait nilai-nilai ke terkait yang. Saya tidak akan merinci tentang hubungan, cukup untuk mengatakan bahwa daftar terkait jika dan hanya jika mereka memiliki panjang yang sama dan unsur-unsurnya terkait pasangan (yaitu,[x_1, x_2, ..., x_m]
dan[y_1, y_2, ..., y_n]
terkait jika dan hanya jikam = n
danx_1
terkait dengany_1
danx_2
terkait dengany_2
dan seterusnya). Dan bagian yang menyenangkan adalah, dalam kasus kami, karenaf
bersifat polimorfik, kita dapat mendefinisikan hubungan apa pun pada elemen daftar!Mari kita pilih
'a
,'b
dan lihatf : 'a list -> 'b list
. Sekarang lihatf : 'a list -> bool list
; kami telah menunjukkan bahwa dalam hal inif
selalu mengembalikan daftar kosong. Kami sekarang mendalilkan bahwa semua elemen'a
terkait dengan diri mereka sendiri (ingat, kita dapat memilih hubungan apa pun yang kita inginkan), ini menyiratkan bahwa adazs : 'a list
yang terkait dengan dirinya sendiri. Seperti kita ketahui,f
mengambil nilai terkait dengan yang terkait, ini berarti yangf zs : 'b list
terkait denganf zs : bool list
, tetapi daftar kedua memiliki panjang sama dengan nol, dan karena yang pertama terkait dengan itu, juga kosong.Untuk kelengkapan, saya akan menyebutkan bahwa ada bagian tentang dampak rekursi umum (kemungkinan non-terminasi) dalam makalah asli Wadler, dan ada juga makalah yang mengeksplorasi teorema bebas di hadapan
seq
.sumber
g
danh
dalam kasus ini) langsung dengan hubungan umum yang dibuat khusus ...Mari kita kembali ke objek yang lebih sederhana: Anda tidak dapat membangun objek jenis yang tepat
'a
karena itu berarti objek inix
dapat digunakan di mana pun'a
cocok. Dan itu berarti di mana-mana: sebagai integer, array, bahkan fungsi. Misalnya itu berarti Anda dapat melakukan hal-hal sepertix+2
,x.(1)
dan(x 5)
. Jenis ada persis untuk mencegah hal ini.Ini ide yang sama yang berlaku dengan fungsi tipe
'a -> 'b
, tetapi ada beberapa kasus di mana tipe ini bisa ada: ketika fungsi tidak pernah mengembalikan objek tipe'b
: ketika perulangan atau menaikkan pengecualian.Ini juga berlaku untuk fungsi yang mengembalikan daftar. Jika fungsi Anda bertipe
t -> 'b list
dan Anda membangun objek bertipet
dan menerapkannya pada fungsi ini, maka itu berarti bahwa jika Anda berhasil mengakses elemen daftar ini maka Anda akan mengakses ke objek yang memiliki semua tipe. Jadi, Anda tidak dapat mengakses elemen daftar mana pun: daftarnya kosong atau ... tidak ada daftar.Namun tipe tersebut
'a list -> 'b list
muncul dalam latihan biasa tapi itu hanya ketika Anda sudah memiliki fungsi tipe'a -> 'b
:Tapi Anda mungkin tahu yang ini.
sumber
'a -> 'b
atau'a list -> 'b list
, tapi itu bukan pengamatan yang menarik. Sebenarnya saya akan mengedit pertanyaan untuk memperjelas ini bukan apa yang dipikirkan oleh siswa yang lebih muda belajar pemrograman.f : 'a list -> 'b list
dant
sehinggaf t <> []
maka program ini akan ketik-cek tetapi dapat melakukannya dengan cara lebih buruk daripada menaikkan pengecualian:let y = List.hd (f t) in (y y) (y + y.(0) + y.(0).(0))
.Teorema Parametrik dari “Teorema Gratis!” makalah memberitahu kita bahwa istilah ML memiliki properti yang sangat istimewa: jika kita melihat jenis istilah sebagai hubungan pada nilai-nilai jenis ini, maka nilai istilah ini akan terkait dengan dirinya sendiri. Berikut ini cara melihat jenis sebagai relasi:
'a -> 'b
sesuai dengan relasi yang didefinisikan dengan mengatakan bahwa dua fungsi terkait jika mereka mengambil nilai terkait ke nilai terkait (dengan asumsi'a
dan'b
sesuai dengan beberapa relasi).'a list
sesuai dengan relasi yang didefinisikan dengan mengatakan bahwa dua daftar terkait jika mereka memiliki panjang yang sama dan elemen-elemen pencocokannya terkait (dengan asumsi'a
sesuai dengan beberapa relasi).Berikut ini sebuah contoh. Misalkan kita memiliki istilahSEBUAH1 dan SEBUAH2 , pilih mutlak hubungan apa pun SEBUAH antara elemen jenis ini, dan jika kita mengambil Sebuah1:SEBUAH1 dan Sebuah2:SEBUAH2 , sehingga mereka terkait menurut SEBUAH , kemudian fooSebuah1 dan fooSebuah2 juga akan terkait sesuai dengan SEBUAH :
foo : 'a -> 'a
. Teorema Parametrik mengatakan bahwafoo
itu terkait dengan dirinya sendiri. Artinya, kita dapat memilih dua jenis, katakan,Sekarang jika kita ambil relasinyaSEBUAH menjadi bukan hubungan yang sewenang-wenang, tetapi suatu fungsi f:SEBUAH1→SEBUAH2 , yang di atas menjadi:
atau, dengan kata lain:
yang persis teorema bebas untuk
id
fungsi:f . id = id . f
.Jika Anda melakukan langkah-langkah serupa untuk fungsiSEBUAH1 dan SEBUAH2 , hubungan apa pun SEBUAH di antara elemen-elemennya, ada dua jenis B1 dan B2 , hubungan apa pun B antara elemen-elemen mereka, lalu ambil dua daftar, yang pertama terbuat dari elemen SEBUAH1 , kedua terbuat dari elemen SEBUAH2 , terapkan fungsi Anda ke kedua daftar (dapatkan daftar B1 dalam kasus pertama dan daftar B2 di yang kedua), dan hasilnya akan terkait, jika input terkait.
foo : 'a list -> 'b list
Anda, Anda akan dapat memilih dua jenisSekarang kami menggunakan ini untuk membuktikan bahwa untuk dua jenis
A
danB
fungsifoo
mengembalikan daftar kosong untuk input apa punas : A list
.A
dan biarkanØ
,B
danas
terkait dengan dirinya sendiri (karena kami memilih hubungan identitas padaA
), dengan demikianfoo as : Ø list
terkait denganfoo as : B list
.Ø
tipe tersebut.Karena itu, untuk apa pun
A
,B
danas : A list
kita harusfoo as : B list
memiliki daftar kosong.sumber