Seberapa penting konsep lanjutan Haskell seperti Monads dan Functors Applicative untuk sebagian besar tugas pemrograman rutin?


16

Saya telah membaca buku Learn You a Haskell sampai pada titik di mana mereka memperkenalkan Monads dan hal-hal seperti Just a. Ini sangat berlawanan dengan intuisi saya sehingga saya merasa ingin berhenti mencoba mempelajarinya.

Tetapi saya benar-benar ingin mencoba.

Saya bertanya-tanya apakah saya setidaknya dapat menghindari konsep-konsep lanjutan untuk sementara waktu dan baru mulai menggunakan bagian lain dari bahasa untuk melakukan banyak tugas praktis dengan bagian-bagian yang lebih mendasar dari Haskell, yaitu fungsi, IO standar, penanganan file, antarmuka database dan sejenisnya.

Apakah ini pendekatan yang masuk akal untuk mempelajari cara menggunakan Haskell?


2
Saya tidak tahu seberapa jauh Anda akan dapatkan. Tanpa monads, Anda tidak dapat melakukan apa pun yang berguna di Haskell, karena melakukan sesuatu yang berguna dalam pemrograman (seperti, menulis program serius yang benar-benar ingin digunakan seseorang) memerlukan I / O dan menyatakan, keduanya hanya dapat dikelola di Haskell melalui penggunaan monad.
Mason Wheeler

1
@dan - Saya akhirnya mengerti monad Haskell dari membaca dua dokumen - "Anda bisa menemukan monad" dan "Menangani Pasukan Awkward". Saya tidak bisa mengatakan apakah mereka lebih baik daripada "Learn You a Haskell", yang belum saya baca, tetapi mereka berhasil untuk saya. Untuk menggunakan notasi dengan IO monad, Anda dapat bertahan dengan sedikit pemahaman tentang apa itu monad - Anda akan melakukan beberapa hal yang akan membuat para ahli tertawa atau menangis, tetapi setidaknya secara dangkal, itu tidak jauh berbeda dari menggunakan bahasa imperatif konvensional. Tapi itu adalah berharga mendapatkan beberapa pemahaman yang lebih dalam.
Steve314

2
@dan, saya butuh hampir satu dekade untuk bosan dengan OOP dan mulai menghargai / ingin tahu tentang bahasa fungsional. Saya masih akan belajar F # dan Clojure sebelum saya mencoba Haskell secara serius. Meskipun tantangan pribadi itu baik, ada sesuatu yang bisa dikatakan tentang perasaan Anda dan jalan perlawanan yang paling sedikit. Banyak tergantung pada siapa Anda. Jika Anda adalah tipe yang sangat matematis, maka Anda mungkin akan menyukai Haskell / Schem sejak awal. Jika Anda lebih dari seorang pria 'menyelesaikannya', tidak apa-apa juga. Jangan mendekati Haskell dengan sikap 'lakukan atau mati'. Terus belajar hal-hal lain, dan ketika bosan kembali.
Pekerjaan

Terima kasih atas nasihatnya. Saya telah mencoba Clojure sebentar, tetapi sintaks Lisp benar-benar tidak bekerja untuk saya, untuk membaca dan mengetik. Saya menemukan sintaksis Haskell lebih alami. Saya senang menggunakan Ruby untuk proyek sementara, tetapi saya berharap untuk mulai melakukan beberapa proyek praktis di Haskell.
dan

@dan, Lucu, saya menemukan sintaks Clojure agak ramah, tapi itu mungkin karena saya pernah terkena Skema sebelumnya. Mungkin setelah F # saya akan terbiasa dengan cara Haskell melakukan sesuatu.
Pekerjaan

Jawaban:


16

Pertama mari kita bedakan antara mempelajari konsep-konsep abstrak dan mempelajari contoh-contoh spesifiknya .

Anda tidak akan terlalu jauh mengabaikan semua contoh spesifik, karena alasan sederhana bahwa mereka benar-benar ada di mana-mana. Faktanya, abstraksi ada sebagian besar karena mereka menyatukan hal-hal yang akan Anda lakukan dengan contoh-contoh spesifik.

Abstraksi itu sendiri, di sisi lain, tentu berguna , tetapi mereka tidak segera diperlukan. Anda bisa mengabaikan abstraksi sepenuhnya dan hanya menggunakan berbagai jenis secara langsung. Anda akan ingin memahami mereka pada akhirnya, tetapi Anda selalu dapat kembali lagi nanti. Bahkan, saya hampir dapat menjamin bahwa jika Anda melakukan itu, ketika Anda kembali ke sana Anda akan menampar dahi Anda dan bertanya-tanya mengapa Anda menghabiskan semua waktu itu melakukan hal-hal dengan cara yang sulit daripada menggunakan alat tujuan umum yang nyaman.

Ambil Maybe asebagai contoh. Itu hanya tipe data:

data Maybe a = Just a | Nothing

Semuanya mendokumentasikan diri; ini merupakan nilai opsional. Entah Anda memiliki "hanya" sesuatu jenis a, atau Anda tidak punya apa-apa. Katakanlah Anda memiliki fungsi pencarian, yang kembali Maybe Stringuntuk mewakili mencari Stringnilai yang mungkin tidak ada. Jadi Anda mencocokkan pola pada nilai untuk melihat yang mana itu:

case lookupFunc key of
    Just val -> ...
    Nothing  -> ...

Itu saja!

Sungguh, tidak ada lagi yang Anda butuhkan. Tidak ada Functors atau Monads atau apa pun. Itu mengungkapkan cara umum menggunakan Maybe anilai ... tapi itu hanya idiom, "pola desain", apa pun yang Anda ingin menyebutnya.

Satu-satunya tempat Anda benar-benar tidak bisa menghindarinya sepenuhnya adalah dengan IO, tetapi itu adalah kotak hitam yang misterius, jadi tidak ada gunanya mencoba memahami apa artinya sebagai Monadatau apa pun.

Sebenarnya, inilah lembar contekan untuk semua yang benar - benar perlu Anda ketahui IOuntuk saat ini:

  • Jika sesuatu memiliki tipe IO a, itu berarti prosedur yang melakukan sesuatu dan mengeluarkan anilai.

  • Ketika Anda memiliki blok kode menggunakan donotasi, tulis sesuatu seperti ini:

    do -- ...
       inp <- getLine
       -- etc...
    

    ... berarti menjalankan prosedur di sebelah kanan <-, dan menetapkan hasilnya ke nama di sebelah kiri.

  • Sedangkan jika Anda memiliki sesuatu seperti ini:

    do -- ...
       let x = [foo, bar]
       -- etc...
    

    ... itu berarti menetapkan nilai ekspresi polos (bukan prosedur) di sebelah kanan =untuk ke nama di sebelah kiri.

  • Jika Anda meletakkan sesuatu di sana tanpa menetapkan nilai, seperti ini:

    do putStrLn "blah blah, fishcakes"
    

    ... artinya menjalankan prosedur dan mengabaikan apa pun yang dikembalikan. Beberapa prosedur memiliki tipe IO ()- ()tipe ini adalah semacam placeholder yang tidak mengatakan apa-apa, sehingga hanya berarti prosedur melakukan sesuatu dan tidak mengembalikan nilai. Agak seperti voidfungsi dalam bahasa lain.

  • Menjalankan prosedur yang sama lebih dari satu kali dapat memberikan hasil yang berbeda; itu semacam ide. Inilah sebabnya mengapa tidak ada cara untuk "menghapus" IOdari nilai, karena sesuatu di dalam IObukan nilai, itu adalah prosedur untuk mendapatkan nilai.

  • Baris terakhir dalam sebuah doblok harus berupa prosedur sederhana tanpa penugasan, di mana nilai balik dari prosedur itu menjadi nilai balik untuk seluruh blok. Jika Anda ingin nilai kembali menggunakan beberapa nilai yang telah ditetapkan, returnfungsi tersebut mengambil nilai polos dan memberi Anda prosedur larangan yang mengembalikan nilai itu.

  • Selain itu, tidak ada yang istimewa tentang IO; prosedur-prosedur ini sebenarnya adalah nilai-nilai sederhana itu sendiri, dan Anda dapat menyebarkannya dan menggabungkannya dengan cara yang berbeda. Hanya ketika mereka dieksekusi di doblok yang disebut di suatu tempat di mainmana mereka melakukan apa pun.

Jadi, dalam sesuatu seperti program contoh stereotip yang benar-benar membosankan ini:

hello = do putStrLn "What's your name?"
           name <- getLine
           let msg = "Hi, " ++ name ++ "!"
           putStrLn msg
           return name

... Anda dapat membacanya seperti program penting. Kami mendefinisikan prosedur bernama hello. Ketika dieksekusi, terlebih dahulu ia menjalankan prosedur untuk mencetak pesan yang menanyakan nama Anda; selanjutnya ia menjalankan prosedur yang membaca sebaris input, dan memberikan hasilnya kepada name; lalu memberikan ekspresi pada nama msg; lalu ia mencetak pesan; lalu mengembalikan nama pengguna sebagai hasil dari seluruh blok. Karena namea String, ini berarti helloprosedur yang mengembalikan a String, sehingga memiliki tipe IO String. Dan sekarang Anda dapat menjalankan prosedur ini di tempat lain, sama seperti itu dijalankan getLine.

Pfff, monad. Siapa yang butuh mereka?


2
@dan: Terima kasih kembali! Jika Anda memiliki pertanyaan spesifik di sepanjang jalan, jangan ragu untuk bertanya di Stack Overflow. Tag [haskell] biasanya cukup aktif di sini, dan jika Anda menjelaskan dari mana Anda berasal orang cukup pandai membantu Anda mendapatkan pemahaman daripada hanya melemparkan jawaban samar.
CA McCann

9

Seberapa penting konsep lanjutan Haskell seperti Monads dan Functors Applicative untuk sebagian besar tugas pemrograman rutin?

Mereka sangat penting. Tanpa mereka, terlalu mudah untuk menggunakan Haskell sebagai bahasa imperatif lainnya, dan meskipun Simon Peyton Jones pernah memanggil Haskell, "bahasa pemrograman imperatif terbaik di dunia", Anda masih melewatkan bagian terbaiknya.

Monads, Monad Transforms, Monoids, Functors, Functors Applicative, Functors Contravarient, Arrows, Categories, dll, adalah pola desain. Setelah Anda memasukkan hal spesifik yang Anda buat menjadi salah satunya, Anda dapat memanfaatkan banyak sekali fungsi yang ditulis secara abstrak. Kelas-tipe ini tidak hanya membuat Anda bingung, mereka ada di sana untuk membuat hidup Anda lebih mudah dan membuat Anda lebih produktif. Mereka, menurut pendapat saya, alasan terbesar untuk keringkasan kode Haskell yang baik.


1
+1: Terima kasih telah menunjukkan bahwa "Monad, Monad Transforms, Monoids, Functors, Functors Applicative, Functors Contravarient, Arrows, Categories, dll, adalah pola desain." !
Giorgio

7

Apakah ini benar-benar diperlukan jika Anda hanya ingin menjalankan sesuatu? Tidak.

Apakah perlu jika Anda ingin menulis program Haskell idiomatik yang indah? Benar.

Saat memprogram di Haskell, ada baiknya Anda mengingat dua hal:

  1. Jenis sistem ada untuk membantu Anda. Jika Anda menyusun program Anda dari kode tipeclass-sangat polimorfik, sangat sering Anda bisa masuk ke situasi yang indah di mana jenis fungsi yang Anda inginkan akan memandu Anda ke (satu satu!) Implementasi yang benar .

  2. Berbagai perpustakaan yang tersedia dikembangkan dengan menggunakan prinsip # 1.

Jadi ketika menulis sebuah program di Haskell, saya mulai dengan menulis tipenya. Lalu saya mulai lagi dan menulis beberapa jenis yang lebih umum (dan jika itu bisa menjadi contoh dari kacamata yang ada, semua lebih baik). Lalu saya menulis beberapa fungsi yang memberi saya nilai dari tipe yang saya inginkan. (Lalu saya bermain dengan mereka ghcidan mungkin menulis beberapa tes Periksa cepat.) Dan akhirnya saya rekatkan semuanya main.

Dimungkinkan untuk menulis Haskell jelek yang baru saja menjalankan sesuatu. Tetapi ada banyak lagi yang harus dipelajari setelah Anda mencapai tahap itu.

Semoga berhasil!


1
Terima kasih! Saya telah ragu-ragu antara Clojure dan Haskell, tetapi sekarang saya condong ke Haskell karena betapa orang-orang seperti Anda sangat membantu.
dan

1
Komunitas Haskell tampaknya sangat baik dan bermanfaat. Dan sepertinya dari situlah banyak ide menarik datang
Zachary K
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.