Sebuah monad adalah hanya sebuah monoid dalam kategori endofunctors, apa's masalah?
Yang pertama kata berikut ini?
monad adalah hanya sebuah monoid dalam kategori endofunctors, apa's masalah?
Dan yang lebih penting diperhatikan, apakah ini benar dan jika demikian anda bisa memberikan penjelasan (mudah-mudahan salah satu yang dapat dipahami oleh seseorang yang doesn't memiliki banyak Haskell pengalaman)?
705
6
Bahwa kata-kata tertentu adalah dengan James Iry, dari-nya yang sangat menghibur Singkat, Lengkap dan Sebagian besar Salah Sejarah Bahasa Pemrograman, di mana ia fictionally atribut ini untuk Philip Wadler.
Kutipan asli dari Saunders Mac Lane dalam Kategori untuk Bekerja Matematika, salah satu dasar teks-teks dari Teori Kategori. Di sini adalah dalam konteks, yang mungkin adalah tempat terbaik untuk belajar persis apa artinya.
Tapi, aku'll mengambil bacokan. Asli kalimat ini:
X berikut adalah kategori. Endofunctors yang functors dari kategori itu sendiri (yang biasanya semua `Functor ini sejauh fungsional programmer yang bersangkutan, karena mereka're kebanyakan berurusan dengan hanya satu kategori; kategori dari jenis - tapi saya ngelantur). Tapi anda bisa bayangkan kategori lain yang merupakan kategori "endofunctors pada X". Ini adalah kategori di mana benda-benda yang endofunctors dan morphisms alami transformasi.
Dan orang-orang endofunctors, beberapa dari mereka mungkin monads. Mana yang monads? Persis orang-orang yang monoidal dalam arti tertentu. Bukan ejaan yang tepat pemetaan dari monads untuk monoids (sejak Mac Lane yang jauh lebih baik daripada yang saya bisa berharap untuk), I'll hanya menempatkan definisi masing-masing sisi dengan sisi dan membiarkan anda membandingkan:
Sebuah monoid adalah...
...memuaskan undang-undang ini:
A monad adalah...
* -> *
denganFunctor
contoh)bergabung
di Haskell)kembali
di Haskell)...memuaskan undang-undang ini:
Dengan sedikit menyipitkan mata anda mungkin bisa melihat bahwa kedua definisi tersebut adalah kasus yang sama abstrak.
Secara intuitif, saya berpikir bahwa apa yang mewah kosakata matematika katakan adalah bahwa:
Monoid
A monoid adalah sekumpulan objek, dan metode menggabungkan mereka. Dikenal monoids adalah:
Ada lebih banyak contoh yang kompleks juga.
Lebih lanjut, setiap monoid memiliki identitas, yang adalah bahwa "no-op" elemen yang tidak memiliki efek ketika anda menggabungkan itu dengan sesuatu yang lain:
Akhirnya, sebuah monoid harus asosiatif. (anda dapat mengurangi string panjang kombinasi yang tetap anda inginkan, asalkan anda don't mengubah kiri-ke-kanan-urutan benda-benda) Itu adalah OK ((5+3)+1 == 5+(3+1)), tapi pengurangan isn't ((5-3)-1 != 5-(3-1)).
Monad
Sekarang, let's mempertimbangkan jenis khusus dari set dan cara khusus untuk menggabungkan objek.
Benda-benda
Misalkan anda set berisi benda-benda dari jenis khusus: fungsi. Dan fungsi-fungsi ini memiliki sebuah tanda tangan yang menarik: Mereka don't membawa angka ke angka atau string ke string. Sebaliknya, fungsi masing-masing membawa sebuah nomor ke daftar nomor yang di proses dua langkah.
Contoh:
Menggabungkan Benda-Benda
Juga, cara menggabungkan fungsi-fungsi khusus. Cara sederhana untuk menggabungkan fungsi komposisi: Let's ambil contoh kita di atas, dan menulis masing-masing fungsi dengan dirinya sendiri:
Tanpa terlalu banyak ke jenis teori, intinya adalah bahwa anda dapat menggabungkan dua bilangan bulat untuk mendapatkan bilangan bulat, tetapi anda dapat't selalu menulis dua fungsi dan mendapatkan fungsi dari jenis yang sama. (Fungsi dengan mengetik a -> sebuah akan menulis, tetapi a-> [a] tidak't.)
Jadi, let's menentukan cara yang berbeda untuk menggabungkan fungsi. Ketika kita menggabungkan dua fungsi ini, kita don't ingin "ganda-bungkus" hasil.
Di sini adalah apa yang kita lakukan. Ketika kita ingin menggabungkan dua fungsi F dan G, kita ikuti proses ini (yang disebut mengikat):
Kembali ke contoh kita, let's menggabungkan (mengikat) fungsi dengan dirinya sendiri menggunakan cara baru "mengikat" fungsi:
Ini cara yang lebih canggih menggabungkan fungsi adalah asosiatif (berikut dari bagaimana fungsi komposisi adalah asosiatif bila anda tidak't melakukan mewah pembungkus barang-barang).
Mengikat semuanya bersama-sama,
Catatan
Ada banyak cara untuk "bungkus" hasil. Anda dapat membuat daftar, atau satu set, atau membuang semua tapi hasil pertama sambil mengingatkan jika tidak ada hasil, pasang sespan dari negara, mencetak pesan log, dll, dll.
I've bermain sedikit longgar dengan definisi-definisi di harapan mendapatkan ide penting di seluruh intuitif.
I've modern hal-hal sedikit dengan bersikeras bahwa kami monad beroperasi pada fungsi dari jenis a -> [a]. Bahkan, monads bekerja pada fungsi dari jenis a -> m b, tetapi generalisasi adalah jenis detail teknis yang isn't utama wawasan.
Pertama, ekstensi dan perpustakaan yang kita're akan menggunakan:
Dari jumlah tersebut,
RankNTypes
adalah satu-satunya yang's benar-benar penting untuk di bawah ini. Saya pernah menulis penjelasan dariRankNTypes
bahwa beberapa orang tampaknya telah menemukan berguna, jadi saya'll lihat itu.Mengutip Tom Crockett's jawaban yang sangat baik, kita memiliki:
Bagaimana kita menerjemahkan ini untuk Haskell kode? Nah, let's mulai dengan gagasan alamitransformasi**:
Jenis bentuk
f :-> g
adalah analog dengan tipe fungsi, tapi bukannya memikirkan hal itu sebagai fungsi antara dua jenis (dari jenis*
), menganggapnya sebagai morphism antara dua functors (masing-masing dari jenis* -> *
). Contoh:Pada dasarnya, di Haskell, alami transformasi fungsi dari beberapa jenis
f x
untuk tipe laing x
seperti itux
jenis variabel adalah "tidak dapat diakses" ke pemanggil. Jadi misalnya,sort :: Ord a => [a] -> [a]
tidak dapat dibuat menjadi transformasi alam, karena itu's "pilih-pilih" tentang yang jenis kita dapat instantiate untuka
. Salah satu cara yang intuitif sering saya gunakan untuk berpikir ini adalah sebagai berikut:Sekarang, dengan keluar dari jalan, let's mengatasi klausul definisi.
Klausa pertama adalah "suatu endofunctor, T : X -> X." Nah, setiap
Functor
di Haskell adalah endofunctor dalam apa yang orang-orang sebut "Hask kategori," benda yang Haskell jenis (jenis*
) dan yang morphisms yang Haskell fungsi. Ini kedengarannya seperti sebuah rumit pernyataan, tapi itu's sebenarnya sangat sepele. Semua itu berarti bahwaFunctor f :: * -> *
memberi anda sarana untuk membangun jenisf a :: *
untuk setiapa :: *
dan fungsifmap f :: f a -> f b
keluar darif :: a -> b
, dan bahwa mereka mematuhi functor undang-undang.Kedua klausa:
Identitas
functor di Haskell (yang datang dengan Platform, sehingga anda hanya dapat mengimpor) didefinisikan dengan cara ini:Sehingga transformasi alam η : I -> T dari Tom Crockett's definisi ini dapat ditulis dengan cara ini untuk setiap
Ketunggalan
misalnyat
:Kalimat ketiga: komposisi dua functors di Haskell dapat didefinisikan dengan cara ini (yang juga dilengkapi dengan Platform):
Sehingga transformasi alam μ : T × T -> T dari Tom Crockett's definisi ini dapat ditulis seperti ini:
Pernyataan bahwa ini adalah sebuah monoid dalam kategori endofunctors maka berarti bahwa
Menulis
(sebagian diterapkan untuk hanya dua parameter pertama) adalah asosiatif, dan bahwaIdentitas
adalah elemen identitas. I. e., yang berikut isomorphisms mengadakan:Menulis f (Compose g h) ~= Menyusun (Compose f g) h
Menulis f Identitas ~= f
Menulis Identitas g ~= g
Ini sangat mudah untuk membuktikan karena
Menulis
danIdentitas
keduanya didefinisikan sebagaitype
, dan Haskell Laporan mendefinisikan semantiktype
sebagai sebuah isomorphism antara jenis yang didefinisikan dan jenis argumen untuktype
's data konstruktor. Jadi misalnya, let's membuktikanMenulis f Identitas ~= f
:Catatan: Tidak ada, ini isn't benar. Di beberapa titik ada komentar di jawaban ini Dan Piponi dirinya mengatakan bahwa penyebab dan efek di sini justru sebaliknya, bahwa ia menulis artikel dalam menanggapi James Iry's menyindir. Tapi itu tampaknya telah dihapus, mungkin oleh beberapa kompulsif lebih rapi.
Di bawah ini adalah asli saya menjawab.
It's sangat mungkin bahwa Iry telah membaca Dari Monoids untuk Monads, sebuah pos di mana Dan Piponi (sigfpe) berasal monads dari monoids di Haskell, dengan banyak diskusi dari kategori teori dan eksplisit menyebutkan "kategori endofunctors pada Hask" . Dalam kasus apapun, siapapun yang bertanya-tanya apa artinya untuk monad menjadi sebuah monoid dalam kategori endofunctors mungkin manfaat dari membaca ini derivasi.
Saya datang ke posting ini dengan cara pemahaman yang lebih baik tentang kesimpulan dari kutipan terkenal dari Mac Lane's Kategori Teori Untuk Bekerja Matematika. Dalam menggambarkan sesuatu, it's sering sama-sama berguna untuk menggambarkan apa itu's tidak. Fakta bahwa Mac Lane menggunakan deskripsi untuk menggambarkan Monad, yang mungkin berarti bahwa hal itu menggambarkan sesuatu yang unik untuk monads. Beruang dengan saya. Untuk mengembangkan pemahaman yang lebih luas dari pernyataan itu, saya percaya itu harus dibuat jelas bahwa dia adalah not menggambarkan sesuatu yang unik untuk monads; pernyataan sama-sama menjelaskan Aplikatif dan Panah antara lain. Untuk alasan yang sama kita dapat memiliki dua monoids pada Int (Produk dan Jumlah), kita dapat memiliki beberapa monoids pada X dalam kategori endofunctors. Tapi ada bahkan lebih untuk kesamaan. Kedua Monad dan Aplikatif memenuhi kriteria:
(misalnya, di hari ke hari
Pohon -> Daftar b
, tapi dalam KategoriPohon -> Daftar
)Pohon -> Daftar
, hanyaDaftar -> Daftar
. Pernyataan menggunakan "Kategori..." Ini mendefinisikan ruang lingkup pernyataan ini. Sebagai contoh, Functor Kategori menjelaskan lingkupf * -> g *
, yaitu,Setiap functor -> Setiap functor
, misalnya,Pohon * -> Daftar *
atauPohon * -> Pohon *
.Apa sebuah pernyataan Kategoris tidak menentukan menjelaskan di mana anything dan semuanya permitted.
Dalam hal ini, dalam functors,
* -> *
akaa -> b
tidak ditentukan yang berartiApa saja -> Apa pun termasuk Sesuatu yang lain
. Sebagai imajinasi saya melompat ke Int -> String, itu juga termasukInteger -> Mungkin Int
, atau bahkanMungkin Ganda,- > Baik String Int
di manaa :: Mungkin Double; b :: Baik berupa String Int
. Jadi pernyataan yang datang bersama-sama sebagai berikut::: f a -> g b
(yaitu, setiap parameter jenis untuk setiap parameter jenis):: f a -> f b
(yaitu, salah satu parameter dengan tipe yang sama parameterized jenis) ... kata secara berbeda,:: objek tunggal -> satu objek
), gagal untuk menggambarkan bahwa saya'm diizinkan untuk menggunakan panah parameterized dengan any number dari monoid nilai-nilai, dari one jenis objek yang diizinkan dalam Monoid. Endo, ~ identitas panah definisi kesetaraan ignores yang functor's type value dan baik jenis dan nilai yang paling dalam, "muatan" lapisan. Dengan demikian, kesetaraan kembalibenar
dalam setiap situasi di mana functorial jenis pertandingan (misalnya,tidak Ada -> Hanya * -> tidak Ada yang
setara denganHanya * -> Hanya * -> Hanya *
karena mereka berduaMungkin -> Mungkin -> Mungkin
).Sidebar: ~ luar konseptual, tetapi adalah yang paling kiri simbol di `f`. Ia juga menjelaskan apa "Haskell" membaca-in pertama (big picture); sehingga Jenis "di luar" dalam kaitannya dengan Jenis Nilai. Hubungan antara lapisan (rantai referensi) dalam pemrograman adalah tidak mudah untuk berhubungan dengan Kategori. Kategori Set digunakan untuk menggambarkan Jenis (Int, String, Mungkin Int dll.) yang termasuk Kategori Functor (parameterized Jenis). Referensi rantai: Functor Jenis, Functor nilai-nilai (elemen yang Functor's set, misalnya, apa-Apa, Hanya), dan pada gilirannya, segala sesuatu yang lain masing-masing functor nilai poin untuk. Dalam Kategori hubungan ini dijelaskan secara berbeda, misalnya, `kembali :: a -> m` dianggap alami transformasi dari satu Functor lain Functor, berbeda dari apa yang disebutkan sejauh ini. Kembali ke thread utama, semua dalam semua, untuk setiap didefinisikan tensor produk dan netral nilai, pernyataan berakhir menggambarkan yang luar biasa kuat komputasi membangun dilahirkan dari paradoks struktur:
:: Daftar
); statislipat
yang mengatakan apa-apa tentang payload)join :: m (m a) -> m
sebagai tensor produk untuk monoidal endofunctor. Namun, itu tidak mengartikulasikan bagaimana, dalam konteks ini, pernyataan,(<*>)
bisa juga juga telah dipilih. Ini benar-benar adalah sebuah contoh dari enam/setengah lusin. Logika untuk menggabungkan nilai-nilai yang persis sama; input yang sama menghasilkan output yang sama dari masing-masing (tidak seperti Produk dan Jumlah monoids untuk Int karena mereka menghasilkan hasil yang berbeda ketika menggabungkan Ints). Jadi, untuk rekap: Sebuah monoid dalam kategori endofunctors menjelaskan:(<*>)
dan(>>=)
keduanya memberikan akses simultan ke duam
nilai-nilai dalam rangka untuk menghitung satu nilai kembali. Logika yang digunakan untuk menghitung nilai kembali adalah persis sama. Jika bukan untuk bentuk yang berbeda dari fungsi-fungsi mereka mengukur (f :: a -> b
versusk :: a -> m b
) dan posisi parameter dengan pengembalian yang sama jenis perhitungan (yaitu,a -> b> b
versusb ->- > b
untuk setiap masing-masing), saya menduga kita bisa memiliki parameter yang monoidal logika, tensor produk, untuk digunakan kembali dalam kedua definisi tersebut. Sebagai latihan untuk membuat titik, mencoba dan menerapkan~t
, dan anda berakhir dengan(<*>)
dan(>>=)
tergantung pada bagaimana anda memutuskan untuk mendefinisikanforall a b
. Jika poin terakhir saya adalah minimal konseptual benar, itu kemudian menjelaskan yang tepat, dan hanya komputasi perbedaan antara Aplikatif dan Monad: fungsi mereka mengukur. Dengan kata lain, perbedaannya adalah external untuk pelaksanaan jenis-jenis kelas. Kesimpulannya, dalam pengalaman saya sendiri, Mac Lane's terkenal kutipan tersebut, "goto" meme, sebuah tonggak bagi saya untuk referensi saat menavigasi jalan melalui Kategori untuk lebih memahami idiom yang digunakan dalam Haskell. Ia berhasil menangkap lingkup kapasitas komputasi yang kuat dibuat sangat mudah diakses di Haskell. Namun, ada ironi dalam bagaimana saya pertama kali disalahpahami pernyataan's penerapan di luar monad, dan apa yang saya harap disampaikan di sini. Segala sesuatu yang menggambarkan ternyata apa yang mirip antara Aplikatif dan Monads (dan Panah antara lain). Apa itu doesn't mengatakan justru yang kecil-kecil tapi berguna perbedaan di antara mereka. - EJawaban di sini melakukan pekerjaan yang sangat baik dalam mendefinisikan kedua monoids dan monads, namun, mereka masih don't tampaknya untuk menjawab pertanyaan:
untuk setiap benda
a,b,c
dariB
, dan identitas yang sama untuk setiap morphismsa,b,c
dengane
diganti denganid_e
, identitas morphism darie
. Sekarang instruktif untuk mengamati bahwa dalam kasus bunga, di manaB
adalah kategori endofunctors dariX
dengan alami transformasi sebagai morphisms,*
yang functor komposisi dane
identitas functor, semua undang-undang ini puas, karena dapat langsung diverifikasi. Apa yang datang setelah dalam buku ini adalah definisi dari "super" monoidal kategori, dimana hukum hanya memegang modulo beberapa tetap alami transformasi memuaskan disebut koherensi hubungan, namun hal ini tidak penting bagi kami kasus endofunctor kategori.Monoids di monoidal kategori
Akhirnya, di bagian 3 "Monoids" Bab VII, yang sebenarnya definisi yang diberikan:
membuat 3 diagram komutatif. Ingat bahwa dalam kasus kami, ini adalah morphisms dalam kategori endofunctors, yang alami transformasi yang sesuai untuk tepatnya
join
dankembali
untuk monad. Koneksi menjadi lebih jelas ketika kita membuat komposisi*
yang lebih eksplisit, menggantic * c
denganc^2
, di manac
adalah kami monad. Akhirnya, perhatikan bahwa 3 diagram komutatif (dalam definisi sebuah monoid dalam monoidal kategori) yang ditulis untuk umum (non-ketat) monoidal kategori, sementara dalam kasus kami semua alami transformasi yang timbul sebagai bagian dari monoidal kategori yang benar-benar identitas. Yang akan membuat diagram persis sama seperti orang-orang dalam pengertian monad, membuat korespondensi lengkap.Kesimpulan
Singkatnya, setiap monad adalah dengan definisi yang endofunctor, maka objek dalam kategori endofunctors, di mana monadic
join
dankembali
operator memenuhi definisi suatu monoid dalam tertentu (ketat) monoidal kategori. Sebaliknya, setiap monoid dalam monoidal kategori endofunctors adalah dengan definisi triple(c, mu, nu)
yang terdiri dari objek dan dua panah, misalnya alam transformasi dalam kasus kami, memuaskan hukum yang sama sebagai monad. Akhirnya, perhatikan perbedaan utama antara (klasik) monoids dan lebih umum monoids di monoidal kategori. Dua panahmu
dannu
di atas tidak lagi biner operasi dan unit dalam satu set. Sebaliknya, anda harus tetap satu endofunctorc
. Yang functor komposisi*
dan identitas functor sendiri tidak memberikan struktur yang lengkap yang dibutuhkan untuk monad, meskipun yang membingungkan komentar di buku ini. Pendekatan lain akan dibandingkan dengan standar monoidC
dari semua self-peta dari kumpulanA
, di mana operasi biner adalah komposisi, yang dapat dilihat untuk memetakan standar produk cartesianC x C
menjadiC
. Lewat ke categorified monoid, kami mengganti produk cartesianx
dengan functor komposisi*
, dan operasi biner akan diganti dengan transformasi alammu
daric * c
untukc
, yang merupakan kumpulan daribergabung
operatoruntuk setiap objek
T
(type dalam pemrograman). Dan identitas unsur-unsur klasik monoids, yang dapat diidentifikasi dengan gambar peta dari tetap satu-titik-set, bisa diganti dengan koleksi yangkembali
operatorTapi sekarang tidak ada lagi cartesian produk, sehingga tidak ada pasangan dari unsur-unsur dan dengan demikian tidak ada operasi biner.