Saya sedang belajar F #. Saya mulai FP dengan Haskell, dan saya ingin tahu untuk ini.
Karena F # adalah bahasa .NET, Tampaknya lebih masuk akal bagi saya untuk mendeklarasikan antarmuka seperti Mappable
, seperti halnya Functor
kelas jenis haskell .
Tapi seperti gambar di atas, fungsi F # dipisahkan dan diimplementasikan sendiri. Apa tujuan desain dari desain semacam itu? Bagi saya, memperkenalkan Mappable.map
dan mengimplementasikan ini untuk setiap tipe data akan lebih mudah.
The community is here to help you with specific coding, algorithm, or language problems.
juga akan mencakup pertanyaan desain bahasa, selama kriteria lainnya terpenuhi.map
dan fungsi tingkat tinggi umum lainnya untuk setiap jenis koleksi. Antarmuka akan sedikit membantu karena masih membutuhkan setiap jenis koleksi untuk menyediakan implementasi yang terpisah.Jawaban:
Ya, pertanyaan yang sangat mudah di permukaan. Tetapi jika Anda meluangkan waktu untuk memikirkannya sampai akhir, Anda masuk ke kedalaman teori jenis yang tak terukur. Dan teori tipe juga menatap Anda.
Pertama, tentu saja, Anda sudah mengetahui dengan benar bahwa F # tidak memiliki kelas tipe, dan itulah sebabnya. Tapi Anda mengusulkan antarmuka
Mappable
. Ok, mari kita lihat itu.Katakanlah kita dapat mendeklarasikan antarmuka semacam itu. Bisakah Anda bayangkan seperti apa tanda tangannya?
Di mana
f
jenis mengimplementasikan antarmuka. Oh tunggu! F # tidak memilikinya juga! Berikutf
adalah variabel tipe yang lebih tinggi, dan F # tidak memiliki jenis yang lebih tinggi sama sekali. Tidak ada cara untuk mendeklarasikan fungsif : 'm<'a> -> 'm<'b>
atau sesuatu seperti itu.Tapi ok, katakanlah kita bisa mengatasi rintangan itu juga. Dan sekarang kita memiliki antarmuka
Mappable
yang dapat diimplementasikan olehList
,Array
,Seq
, dan wastafel dapur. Tapi tunggu! Sekarang kita memiliki metode alih-alih fungsi, dan metode tidak menyusun dengan baik! Mari kita lihat menambahkan 42 ke setiap elemen daftar bersarang:Lihat: sekarang kita harus menggunakan ekspresi lambda! Tidak ada cara untuk meneruskan
.map
implementasi ini ke fungsi lain sebagai nilai. Secara efektif akhir dari "berfungsi sebagai nilai" (dan ya, saya tahu, menggunakan lambda tidak terlihat sangat buruk dalam contoh ini, tapi percayalah, itu menjadi sangat jelek)Tapi tunggu, kita masih belum selesai. Sekarang ini adalah pemanggilan metode, ketik inferensi tidak berfungsi! Karena tipe tanda tangan metode .NET tergantung pada jenis objek, tidak ada cara bagi kompilator untuk menyimpulkan keduanya. Ini sebenarnya adalah masalah yang sangat umum yang dialami pemula ketika beroperasi dengan. Dan satu-satunya obat adalah dengan memberikan tanda tangan jenis:
Oh, tapi ini masih belum cukup! Meskipun saya telah memberikan tanda tangan untuk
nestedList
dirinya sendiri, saya belum memberikan tanda tangan untuk parameter lambdal
. Seperti apa tanda tangan itu? Apakah Anda akan mengatakannyafun (l: #Mappable) -> ...
? Oh, dan sekarang kita akhirnya mendapatkan peringkat-N jenis, karena Anda lihat,#Mappable
adalah jalan pintas untuk "semua jenis'a
seperti itu'a :> Mappable
" - yaitu ekspresi lambda yang sendiri generik.Atau, sebagai alternatif, kita bisa kembali ke kebaikan yang lebih tinggi dan mendeklarasikan tipe yang
nestedList
lebih tepat:Tapi ok, mari kita kesampingkan inferensi tipe untuk saat ini dan kembali ke ekspresi lambda dan bagaimana kita sekarang tidak bisa meneruskan
map
sebagai nilai ke fungsi lain. Katakanlah kita memperluas sedikit sintaks untuk memungkinkan seperti apa yang Elm lakukan dengan bidang rekaman:Seperti apa jadinya
.map
? Itu harus menjadi tipe kendala , seperti di Haskell!Wow, baiklah. Mengesampingkan fakta bahwa .NET bahkan tidak mengizinkan jenis seperti itu ada, secara efektif kita baru saja kembali kelas jenis!
Tetapi ada alasan bahwa F # tidak memiliki kelas tipe di tempat pertama. Banyak aspek dari alasan itu dijelaskan di atas, tetapi cara yang lebih ringkas untuk mengatakannya adalah: kesederhanaan .
Untuk Anda lihat, ini adalah bola benang. Setelah Anda memiliki kelas tipe, Anda harus memiliki kendala, jenis yang lebih tinggi, peringkat-N (atau setidaknya peringkat-2), dan sebelum Anda menyadarinya, Anda meminta jenis yang tidak tepat, fungsi tipe, GADT, dan semua sisanya.
Tapi Haskell membayar harga untuk semua barang. Ternyata tidak ada cara yang baik untuk menyimpulkan semua hal itu. Jenis yang lebih baik agak bekerja, tetapi kendala sudah agak tidak. Peringkat-N - bahkan tidak memimpikannya. Dan bahkan ketika itu berhasil, Anda mendapatkan kesalahan ketik yang Anda harus memiliki PhD untuk mengerti Dan itu sebabnya di Haskell Anda dengan lembut didorong untuk menaruh tanda tangan ketik pada segalanya. Yah, tidak semuanya - semuanya, tapi benar-benar hampir semuanya. Dan di mana Anda tidak menaruh tanda tangan tipe (misalnya di dalam
let
danwhere
) - kejutan-kejutan, tempat-tempat itu sebenarnya monomorf, jadi Anda pada dasarnya kembali ke tanah F # yang sederhana.Di F #, di sisi lain, tipe tanda tangan jarang, kebanyakan hanya untuk dokumentasi atau untuk .NET interop. Di luar kedua kasus itu, Anda dapat menulis program kompleks besar di F # dan tidak menggunakan tipe tanda tangan sekali pun. Jenis inferensi berfungsi dengan baik, karena tidak ada yang terlalu rumit atau ambigu untuk ditangani.
Dan ini adalah keuntungan besar F # atas Haskell. Ya, Haskell memungkinkan Anda mengekspresikan hal-hal yang sangat kompleks dengan cara yang sangat tepat, itu bagus. Tapi F # membuat Anda menjadi sangat plin-plan, hampir seperti Python atau Ruby, dan masih ada kompiler yang menangkap Anda jika tersandung.
sumber