Siapa yang pertama kali mengatakan yang berikut?
Monad hanya monoid dalam kategori endofunctor, apa masalahnya?
Dan pada catatan yang kurang penting, apakah ini benar dan jika demikian dapatkah Anda memberikan penjelasan (mudah-mudahan yang dapat dipahami oleh seseorang yang tidak memiliki banyak pengalaman Haskell)?
haskell
monads
category-theory
monoids
Roman A. Taycher
sumber
sumber
Jawaban:
Ungkapan khusus itu adalah oleh James Iry, dari Briefnya yang sangat menghibur , Tidak Lengkap, dan Paling Salah Sejarah Bahasa Pemrograman , di mana ia secara fiksi menghubungkannya dengan Philip Wadler.
Kutipan asli dari Saunders Mac Lane di Categories for the Working Mathematician , salah satu teks dasar Category Theory. Ini dia dalam konteks , yang mungkin merupakan tempat terbaik untuk mempelajari dengan tepat apa artinya.
Tapi, saya akan coba. Kalimat aslinya adalah ini:
X di sini adalah kategori. Endofunctors adalah functors dari kategori ke dirinya sendiri (yang biasanya semua
Functor
sejauh menyangkut programmer fungsional, karena mereka kebanyakan berurusan dengan hanya satu kategori; kategori jenis - tapi saya ngelantur). Tetapi Anda bisa membayangkan kategori lain yang merupakan kategori "endofunctors on X ". Ini adalah kategori di mana objek adalah endofunctor dan morfisme adalah transformasi alami.Dan di antara petugas akhir itu, beberapa di antaranya mungkin adalah monad. Yang mana yang merupakan monad? Tepatnya yang monoid dalam arti tertentu. Alih-alih menguraikan pemetaan yang tepat dari monad ke monoid (karena Mac Lane melakukan itu jauh lebih baik daripada yang saya harapkan), saya hanya akan menempatkan definisi masing-masing berdampingan dan membiarkan Anda membandingkan:
Monoid adalah ...
... memenuhi hukum ini:
Monad adalah ...
* -> *
dengan aFunctor
instance)join
dalam Haskell)return
di Haskell)... memenuhi hukum ini:
Dengan sedikit menyipit Anda mungkin dapat melihat bahwa kedua definisi ini adalah contoh dari konsep abstrak yang sama .
sumber
S
adalah tipe, yang dapat Anda lakukan ketika menulis fungsif :: () -> S
adalah memilih beberapa istilah tertentu dari tipeS
("elemen" itu, jika Anda mau) dan kembali itu ... Anda tidak diberi informasi nyata dengan argumennya, jadi tidak ada cara untuk memvariasikan perilaku fungsi. Jadif
harus merupakan fungsi konstan yang hanya mengembalikan hal yang sama setiap waktu.()
("Unit") adalah objek terminal dari kategori Hask , dan bukan kebetulan bahwa ada tepat 1 (non-divergen) nilai yang menghuninya.Secara intuitif, saya berpikir bahwa apa yang dikatakan oleh kosa kata matematika mewah adalah:
Monoid
Sebuah monoid adalah satu set objek, dan metode menggabungkan mereka. Monoids terkenal adalah:
Ada juga contoh yang lebih kompleks.
Lebih lanjut, setiap monoid memiliki identitas , yaitu elemen "tidak-op" yang tidak memiliki efek ketika Anda menggabungkannya dengan sesuatu yang lain:
Akhirnya, monoid harus asosiatif . (Anda dapat mengurangi serangkaian panjang kombinasi yang Anda inginkan, selama Anda tidak mengubah urutan objek dari kiri ke kanan). Penambahan adalah OK ((5 + 3) +1 == 5+ (3+ 1)), tetapi pengurangan bukan ((5-3) -1! = 5- (3-1)).
Monad
Sekarang, mari kita pertimbangkan jenis set khusus dan cara khusus untuk menggabungkan objek.
Benda
Misalkan set Anda berisi objek jenis khusus: fungsi . Dan fungsi-fungsi ini memiliki tanda tangan yang menarik: Mereka tidak membawa angka ke angka atau string ke string. Sebaliknya, setiap fungsi membawa nomor ke daftar angka dalam proses dua langkah.
Contoh:
Menggabungkan Objek
Juga, cara kami menggabungkan fungsi adalah spesial. Cara sederhana untuk menggabungkan fungsi adalah komposisi : Mari kita ambil contoh di atas, dan susun setiap fungsi dengan sendirinya:
Tanpa terlalu banyak ke dalam teori tipe, intinya adalah bahwa Anda dapat menggabungkan dua bilangan bulat untuk mendapatkan bilangan bulat, tetapi Anda tidak selalu dapat membuat dua fungsi dan mendapatkan fungsi dengan tipe yang sama. (Fungsi dengan tipe a -> a akan menulis, tetapi a-> [a] tidak.)
Jadi, mari kita definisikan cara berbeda untuk menggabungkan fungsi. Saat kami menggabungkan dua fungsi ini, kami tidak ingin "membungkus ganda" hasilnya.
Inilah yang kami lakukan. Saat kami ingin menggabungkan dua fungsi F dan G, kami mengikuti proses ini (disebut binding ):
Kembali ke contoh kita, mari kita gabungkan (ikat) fungsi dengan dirinya sendiri menggunakan cara baru fungsi "mengikat" ini:
Cara menggabungkan fungsi yang lebih canggih ini adalah asosiatif (mengikuti dari bagaimana komposisi fungsi asosiatif ketika Anda tidak melakukan hal-hal pembungkus yang bagus).
Mengikat semuanya,
Catatan
Ada banyak cara untuk "membungkus" hasil. Anda dapat membuat daftar, atau set, atau membuang semua kecuali hasil pertama sambil mencatat jika tidak ada hasil, lampirkan sespan keadaan, cetak pesan log, dll, dll.
Saya telah bermain agak longgar dengan definisi dengan harapan mendapatkan ide penting secara intuitif.
Saya telah menyederhanakan banyak hal dengan menegaskan bahwa monad kami beroperasi pada fungsi tipe a -> [a] . Bahkan, monads bekerja pada fungsi tipe a -> mb , tetapi generalisasi adalah semacam detail teknis yang bukan wawasan utama.
sumber
a -> [b]
danc -> [d]
(Anda hanya dapat melakukan ini jikab
=c
), ini tidak cukup menggambarkan monoid a. Ini sebenarnya operasi perataan yang Anda gambarkan, daripada komposisi fungsi, yang merupakan "operator monoid".a -> [a]
, ini akan menjadi monoid (karena Anda akan mengurangi kategori Kleisli menjadi satu objek tunggal, dan kategori apa pun dari satu objek saja menurut definisi adalah monoid!), tetapi itu tidak akan menangkap keseluruhan umum monad.Pertama, ekstensi dan pustaka yang akan kita gunakan:
Dari jumlah tersebut,
RankNTypes
adalah satu-satunya yang mutlak penting untuk di bawah ini. Saya pernah menulis penjelasanRankNTypes
bahwa beberapa orang tampaknya bermanfaat , jadi saya akan merujuknya.Mengutip jawaban Tom Crockett yang luar biasa , kami memiliki:
Bagaimana kita menerjemahkan ini ke kode Haskell? Baiklah, mari kita mulai dengan gagasan transformasi alami :
Jenis bentuk
f :-> g
analog dengan tipe fungsi, tetapi alih-alih menganggapnya sebagai fungsi antara dua jenis (jenis*
), anggap itu sebagai morfisme antara dua fungsi (masing-masing jenis* -> *
). Contoh:Pada dasarnya, di Haskell, transformasi alami adalah fungsi dari beberapa tipe
f x
ke tipe laing x
sehinggax
variabel tipe "tidak dapat diakses" oleh pemanggil. Jadi misalnya,sort :: Ord a => [a] -> [a]
tidak dapat dibuat menjadi transformasi alami, karena itu "pilih-pilih" tentang jenis yang kita instantiatea
. Satu cara intuitif yang sering saya gunakan untuk memikirkan ini adalah sebagai berikut:Sekarang, dengan itu, mari kita bahas pasal-pasal definisi tersebut.
Klausa pertama adalah "seorang endofunctor, T: X -> X. " Nah, setiap orang
Functor
di Haskell adalah endofunctor dalam apa yang orang-orang sebut "kategori Hask," yang objeknya adalah tipe Haskell (sejenis*
) dan yang morfismenya adalah fungsi Haskell. Ini kedengarannya seperti pernyataan yang rumit, tapi itu sebenarnya sangat sepele. Semua itu berarti bahwa aFunctor f :: * -> *
memberi Anda cara membangun tipef a :: *
untuk apa sajaa :: *
dan fungsifmap f :: f a -> f b
dari apa sajaf :: a -> b
, dan bahwa ini mematuhi hukum functor.Klausa kedua:
Identity
functor di Haskell (yang datang dengan Platform, jadi Anda bisa mengimpornya) didefinisikan dengan cara ini:Jadi transformasi alam η: I -> T dari definisi Tom Crockett dapat ditulis dengan cara ini untuk setiap
Monad
misalnyat
:Klausa ketiga: Komposisi dua functors di Haskell dapat didefinisikan dengan cara ini (yang juga dilengkapi dengan Platform):
Jadi transformasi alami μ: T × T -> T dari definisi Tom Crockett dapat ditulis seperti ini:
Pernyataan bahwa ini adalah monoid dalam kategori endofunctor berarti bahwa
Compose
(sebagian diterapkan hanya pada dua parameter pertama) adalah asosiatif, dan ituIdentity
adalah elemen identitasnya. Yaitu, bahwa isomorfisma berikut ini berlaku:Compose f (Compose g h) ~= Compose (Compose f g) h
Compose f Identity ~= f
Compose Identity g ~= g
Ini sangat mudah dibuktikan karena
Compose
danIdentity
keduanya didefinisikan sebagainewtype
, dan Laporan Haskell mendefinisikan semantiknewtype
sebagai isomorfisme antara jenis yang didefinisikan dan jenis argumen kenewtype
konstruktor data. Jadi misalnya, mari kita buktikanCompose f Identity ~= f
:sumber
Natural
tipe baru, saya tidak tahu apa yang dilakukan(Functor f, Functor g)
kendala. Bisakah Anda jelaskan?Functor
kendala itu karena tampaknya tidak perlu. Jika Anda tidak setuju maka silakan menambahkannya kembali.join
didefinisikan. Dan itujoin
adalah morfisme proyeksi. Tapi saya tidak yakin.Catatan: Tidak, ini tidak benar. Pada titik tertentu ada komentar pada jawaban ini dari Dan Piponi sendiri yang mengatakan bahwa sebab dan akibat di sini adalah kebalikannya, bahwa ia menulis artikelnya sebagai tanggapan atas sindiran James Iry. Tetapi tampaknya telah dihapus, mungkin oleh beberapa rapi lebih kompulsif.
Di bawah ini adalah jawaban asli saya.
Sangat mungkin bahwa Iry telah membaca From Monoids to Monads , sebuah pos di mana Dan Piponi (sigfpe) memperoleh monads dari monoids di Haskell, dengan banyak diskusi tentang teori kategori dan menyebutkan secara eksplisit "kategori endofunctors on Hask ". Dalam kasus apa pun, siapa pun yang bertanya-tanya apa artinya sebuah monad menjadi monoid dalam kategori endofunctor mungkin mendapat manfaat dari membaca derivasi ini.
sumber
:-)
.Saya datang ke posting ini dengan cara lebih memahami kesimpulan kutipan terkenal dari Teori Kategori Mac Lane Untuk Matematika yang Bekerja .
Dalam menggambarkan apa itu sesuatu, seringkali sama bermanfaatnya untuk menggambarkan apa itu bukan.
Fakta bahwa Mac Lane menggunakan deskripsi untuk menggambarkan Monad, orang mungkin menyiratkan bahwa itu menggambarkan sesuatu yang unik untuk monad. Tetap bersamaku. Untuk mengembangkan pemahaman yang lebih luas tentang pernyataan itu, saya percaya perlu dijelaskan bahwa dia tidak menggambarkan sesuatu yang unik untuk monad; pernyataan itu sama-sama menggambarkan antara Applicative dan Arrows. Untuk alasan yang sama kita dapat memiliki dua monoids pada Int (Jumlah dan Produk), kita dapat memiliki beberapa monoids pada X dalam kategori endofunctors. Tetapi ada lebih banyak kesamaan.
Baik Monad maupun Aplikatif memenuhi kriteria:
(mis. dalam sehari-hari
Tree a -> List b
, tetapi dalam KategoriTree -> List
)Tree -> List
, hanyaList -> List
.Pernyataan ini menggunakan "Kategori ..." Ini mendefinisikan ruang lingkup pernyataan. Sebagai contoh, Kategori Functor menggambarkan ruang lingkup
f * -> g *
, yaituAny functor -> Any functor
, misalnya,Tree * -> List *
atauTree * -> Tree *
.Apa yang tidak disebutkan dalam pernyataan Kategoris menjelaskan di mana segala sesuatu dan segala sesuatu diizinkan .
Dalam hal ini, di dalam functors,
* -> *
aliasa -> b
tidak ditentukan artinyaAnything -> Anything including Anything else
. Ketika imajinasi saya melompat ke Int -> String, itu juga termasukInteger -> Maybe Int
, atau bahkan diMaybe Double -> Either String Int
manaa :: Maybe Double; b :: Either String Int
.Jadi pernyataan itu muncul bersama sebagai berikut:
:: f a -> g b
(yaitu, semua tipe parameter untuk semua tipe parameter):: f a -> f b
(yaitu, salah satu jenis parameter untuk jenis parameter yang sama) ... berkata berbeda,Jadi, di mana kekuatan konstruksi ini? Untuk menghargai dinamika penuh, saya perlu melihat bahwa gambar tipikal monoid (objek tunggal dengan apa yang tampak seperti panah identitas
:: single object -> single object
), gagal menggambarkan bahwa saya diizinkan menggunakan panah yang diparameterisasi dengan sejumlah nilai monoid, dari objek satu jenis yang diizinkan dalam Monoid. Definisi tanda panah endo, ~ identitas tentang kesetaraan mengabaikan nilai tipe functor dan baik tipe maupun nilai dari lapisan "payload" yang paling dalam. Dengan demikian, kesetaraan kembalitrue
dalam situasi apa pun di mana jenis fungsi cocok (misalnya,Nothing -> Just * -> Nothing
setara denganJust * -> Just * -> Just *
karena keduanyaMaybe -> Maybe -> Maybe
).Bilah samping: ~ luar adalah konseptual, tetapi merupakan simbol paling kiri di
f a
. Ini juga menggambarkan apa yang "Haskell" baca pertama (gambaran besar); jadi Ketik adalah "luar" dalam kaitannya dengan Nilai Jenis. Hubungan antar lapisan (rangkaian referensi) dalam pemrograman tidak mudah dihubungkan dalam Kategori. Kategori Set digunakan untuk menggambarkan Jenis (Int, String, Mungkin Int dll.) Yang mencakup Kategori Functor (Tipe parameter). Rantai referensi: Jenis Functor, nilai-nilai Functor (elemen-elemen dari set Functor itu, misalnya, Tidak Ada, Hanya), dan pada gilirannya, segala sesuatu yang ditunjuk oleh masing-masing nilai functor. Dalam Kategori hubungan dijelaskan secara berbeda, misalnya,return :: a -> m a
dianggap sebagai transformasi alami dari satu Functor ke Functor lain, berbeda dari apa pun yang disebutkan sejauh ini.Kembali ke utas utama, secara keseluruhan, untuk setiap produk tensor yang ditentukan dan nilai netral, pernyataan tersebut akhirnya menggambarkan konstruksi komputasi yang sangat kuat yang lahir dari struktur paradoksnya:
:: List
); statisfold
yang tidak mengatakan apa-apa tentang payload)Di Haskell, memperjelas penerapan pernyataan itu penting. Kekuatan dan fleksibilitas dari konstruk ini, sama sekali tidak ada hubungannya dengan monad per se . Dengan kata lain, konstruk tidak bergantung pada apa yang membuat monad unik.
Ketika mencoba mencari tahu apakah akan membangun kode dengan konteks bersama untuk mendukung perhitungan yang saling bergantung satu sama lain, dibandingkan perhitungan yang dapat dijalankan secara paralel, pernyataan terkenal ini, dengan sebanyak yang dijelaskan, tidak kontras antara pilihan Applicative, Arrows and Monads, tetapi lebih merupakan deskripsi dari seberapa banyak mereka sama. Untuk keputusan yang diambil, pernyataan itu bisa diperdebatkan.
Ini sering disalahpahami. Pernyataan itu selanjutnya menggambarkan
join :: m (m a) -> m a
sebagai produk tensor untuk endofunctor monoid. Namun, itu tidak mengartikulasikan bagaimana, dalam konteks pernyataan ini,(<*>)
juga bisa dipilih. Ini benar-benar adalah contoh enam / setengah lusin. Logika untuk menggabungkan nilai-nilai persis sama; input yang sama menghasilkan output yang sama dari masing-masing (tidak seperti jumlah dan monoid Produk untuk Int karena mereka menghasilkan hasil yang berbeda ketika menggabungkan Ints).Jadi, untuk rekap: Monoide dalam kategori endofunctors menggambarkan:
(<*>)
dan(>>=)
keduanya memberikan akses simultan ke duam
nilai untuk menghitung nilai pengembalian tunggal. Logika yang digunakan untuk menghitung nilai kembali persis sama. Jika bukan karena bentuk yang berbeda dari fungsi yang mereka parameterkan (f :: a -> b
versusk :: a -> m b
) dan posisi parameter dengan tipe pengembalian yang sama dari perhitungan (yaitu,a -> b -> b
dibandingkanb -> a -> b
untuk masing-masing), saya curiga kita bisa parameter logika monoid, produk tensor, untuk digunakan kembali dalam kedua definisi. Sebagai latihan untuk menyampaikan maksud, cobalah dan terapkan~t
, dan Anda berakhir dengan(<*>)
dan(>>=)
tergantung pada bagaimana Anda memutuskan untuk mendefinisikannyaforall a b
.Jika poin terakhir saya paling tidak secara konsepsi benar, maka itu menjelaskan perbedaan komputasi yang tepat, dan hanya antara Applicative dan Monad: fungsi yang mereka parameterkan. Dengan kata lain, perbedaannya adalah eksternal untuk implementasi kelas tipe ini.
Kesimpulannya, dalam pengalaman saya sendiri, kutipan terkenal dari Mac Lane memberikan meme "goto" yang luar biasa, sebuah patokan bagi saya untuk referensi sambil menavigasi jalan saya melalui Kategori untuk lebih memahami idiom yang digunakan dalam Haskell. Ini berhasil menangkap ruang lingkup kapasitas komputasi yang kuat yang dapat diakses dengan luar biasa di Haskell.
Namun, ada ironi dalam cara saya pertama kali salah memahami penerapan pernyataan di luar monad, dan apa yang saya harap sampaikan di sini. Segala sesuatu yang dijelaskannya ternyata mirip dengan yang berlaku antara Applicative dan Monads (dan Arrows antara lain). Apa yang tidak dikatakannya adalah perbedaan kecil tapi bermanfaat di antara mereka.
- E
sumber
Jawaban di sini melakukan pekerjaan yang sangat baik dalam mendefinisikan baik monoid maupun monad, namun, mereka masih belum menjawab pertanyaan:
Inti dari masalah yang hilang di sini, adalah gagasan yang berbeda tentang "monoid", yang disebut kategorisasi lebih tepatnya - yang monoid dalam kategori monoid. Buku Sadly Mac Lane sendiri membuatnya sangat membingungkan :
Kebingungan utama
Mengapa ini membingungkan? Karena tidak mendefinisikan apa yang "monoid dalam kategori endofunctors" dari
X
. Sebaliknya, kalimat ini menyarankan mengambil monoid di dalam himpunan semua endofunctor bersama-sama dengan komposisi functor sebagai operasi biner dan functor identitas sebagai unit monoid. Yang berfungsi sangat baik dan berubah menjadi monoid bagian dari endofunctor yang berisi functor identitas dan ditutup di bawah komposisi functor.Namun ini bukan interpretasi yang benar, yang gagal dijelaskan oleh buku ini pada tahap itu. Monad
f
adalah endofunctor tetap , bukan bagian dari endofunctor yang ditutup berdasarkan komposisi. Sebuah konstruksi umum adalah dengan menggunakanf
untuk menghasilkan monoid dengan mengambil himpunan semuak
komposisi gandaf^k = f(f(...))
darif
dengan dirinya sendiri, termasukk=0
yang sesuai dengan identitasf^0 = id
. Dan sekarang himpunanS
semua kekuatan ini untuk semuak>=0
memang monoid "dengan produk × digantikan oleh komposisi endofunctor dan unit yang ditetapkan oleh endofunctor identitas".Dan lagi:
S
dapat didefinisikan untuk setiap functorf
atau bahkan secara harfiah untuk setiap peta diriX
. Ini adalah monoid yang dihasilkan olehf
.S
diberikan oleh komposisi functor dan functor identitas tidak ada hubungannya denganf
menjadi atau tidak menjadi monad.Dan untuk membuat hal-hal lebih membingungkan, definisi "monoid dalam kategori monoid" muncul nanti dalam buku seperti yang dapat Anda lihat dari daftar isi . Namun memahami gagasan ini sangat penting untuk memahami hubungan dengan monad.
(Ketat) kategori monoid
Pergi ke Bab VII tentang monoids (yang datang kemudian dari Bab VI tentang monad), kita menemukan definisi yang disebut kategori monoidal ketat sebagai tiga
(B, *, e)
, di manaB
adalah kategori,*: B x B-> B
sebuah bifunctor (functor terhadap masing-masing komponen dengan komponen lainnya tetap ) dane
merupakan objek satuanB
, yang memenuhi asosiatif dan hukum unit:untuk setiap benda
a,b,c
dariB
, dan identitas yang sama untuk setiap morphismsa,b,c
dengane
digantikan olehid_e
, para morphism identitase
. Sekarang menjadi pelajaran untuk mengamati bahwa dalam kasus yang kami minati, di manaB
kategori endofunctorX
dengan transformasi alami sebagai morfisme,*
komposisi functor dane
functor identitas, semua undang-undang ini dipenuhi, seperti yang dapat diverifikasi secara langsung.Apa yang muncul setelahnya dalam buku ini adalah definisi dari kategori monoid "santai" , di mana hukum hanya menahan modulo beberapa transformasi alami tetap yang memuaskan apa yang disebut hubungan koherensi , yang bagaimanapun tidak penting bagi kasus kategori endofunctor kami.
Monoids dalam kategori monoid
Akhirnya, dalam bagian 3 "Monoids" dari Bab VII, definisi aktual diberikan:
membuat 3 diagram komutatif. Ingatlah bahwa dalam kasus kami, ini adalah morfisme dalam kategori endofunctor, yang merupakan transformasi alami yang sesuai dengan tepat
join
danreturn
untuk monad. Koneksi menjadi lebih jelas ketika kita membuat komposisi*
lebih eksplisit, menggantikanc * c
denganc^2
, di manac
monad kita.Akhirnya, perhatikan bahwa 3 diagram komutatif (dalam definisi monoid dalam kategori monoid) ditulis untuk kategori monoid umum (non-ketat), sedangkan dalam kasus kami semua transformasi alami yang timbul sebagai bagian dari kategori monoid sebenarnya adalah identitas. Itu akan membuat diagram persis sama dengan yang ada di definisi monad, membuat korespondensi selesai.
Kesimpulan
Singkatnya, setiap monad secara definisi adalah endofunctor, maka objek dalam kategori endofunctor, di mana monadik
join
danreturn
operator memenuhi definisi monoid dalam kategori monoidal (ketat) tertentu . Begitu pula sebaliknya, setiap monoid dalam kategori monoid endofunctor secara definisi adalah triple yang(c, mu, nu)
terdiri dari sebuah objek dan dua panah, misalnya transformasi alami dalam kasus kami, memenuhi hukum yang sama dengan monad.Akhirnya, perhatikan perbedaan utama antara monoids (klasik) dan monoids yang lebih umum dalam kategori monoid. Dua panah
mu
dan dinu
atas bukan lagi operasi biner dan unit dalam satu set. Sebagai gantinya, Anda memiliki satu endofunctor tetapc
. Komposisi functor*
dan functor identitas saja tidak menyediakan struktur lengkap yang diperlukan untuk monad, meskipun ada komentar membingungkan dalam buku ini.Pendekatan lain akan membandingkan dengan monoid standar
C
dari semua diri-peta setA
, di mana operasi biner adalah komposisi, yang dapat dilihat untuk memetakan produk Cartesian standarC x C
dalamC
. Melewati monoid yang dikategorikan, kami mengganti produk kartesiusx
dengan komposisi functor*
, dan operasi biner diganti dengan transformasi alamimu
daric * c
menjadic
, yaitu kumpulanjoin
operatoruntuk setiap objek
T
(ketik pemrograman). Dan elemen-elemen identitas dalam monoids klasik, yang dapat diidentifikasi dengan gambar-gambar peta dari satu-set-set tetap, diganti dengan koleksireturn
operatorTetapi sekarang tidak ada lagi produk kartesius, sehingga tidak ada pasangan elemen dan dengan demikian tidak ada operasi biner.
sumber