Sambil menjelaskan kepada seseorang apa tipe kelas X itu, saya berjuang untuk menemukan contoh struktur data yang tepat yaitu X.
Jadi, saya meminta contoh untuk:
- Tipe konstruktor yang bukan merupakan Functor.
- Tipe konstruktor yang merupakan Functor, tetapi tidak berlaku.
- Tipe konstruktor yang merupakan Aplikasi, tetapi bukan Monad.
- Tipe konstruktor yang merupakan Monad.
Saya pikir ada banyak contoh Monad di mana-mana, tetapi contoh yang baik dari Monad dengan beberapa kaitannya dengan contoh-contoh sebelumnya dapat melengkapi gambarannya.
Saya mencari contoh yang akan mirip satu sama lain, hanya berbeda dalam aspek-aspek penting untuk menjadi milik kelas tipe tertentu.
Jika seseorang berhasil menyelinap contoh Arrow di suatu tempat dalam hierarki ini (apakah itu antara Applicative dan Monad?), Itu akan menjadi hebat juga!
haskell
monads
functor
applicative
Rotsor
sumber
sumber
* -> *
) yang terdapat ada yang cocokfmap
?a -> String
bukan functor.a -> String
adalah functor matematika, tetapi bukan HaskellFunctor
, harus jelas.(a -> b) -> f b -> f a
Jawaban:
Tipe konstruktor yang bukan merupakan Functor:
Anda dapat membuat functor kontravarian darinya, tetapi bukan functor (kovarian). Cobalah menulis
fmap
dan Anda akan gagal. Perhatikan bahwa versi fungsi contravarian terbalik:Tipe konstruktor yang merupakan functor, tetapi tidak berlaku:
Saya tidak punya contoh yang baik. Memang ada
Const
, tetapi idealnya saya ingin yang non-monoid dan saya tidak bisa memikirkannya. Semua tipe pada dasarnya numerik, enumerasi, produk, jumlah, atau fungsi saat Anda melakukannya. Anda dapat melihat di bawah ini pekerja pigmen dan saya tidak setuju tentang apakahData.Void
ituMonoid
;Karena
_|_
nilai legal di Haskell, dan pada kenyataannya satu-satunya nilai legalData.Void
, ini memenuhi aturan Monoid. Saya tidak yakin apa yangunsafeCoerce
harus dilakukan dengan itu, karena program Anda tidak lagi dijamin tidak akan melanggar semantik Haskell segera setelah Anda menggunakanunsafe
fungsi apa pun .Lihat Haskell Wiki untuk artikel di bagian bawah ( tautan ) atau fungsi tidak aman ( tautan ).
Saya ingin tahu apakah mungkin untuk membuat konstruktor tipe seperti itu menggunakan sistem tipe yang lebih kaya, seperti Agda atau Haskell dengan berbagai ekstensi.
Tipe konstruktor yang merupakan Aplikasi, tetapi bukan Monad:
Anda dapat membuat Applicative darinya, dengan sesuatu seperti:
Tetapi jika Anda menjadikannya monad, Anda bisa mendapatkan dimensi ketidakcocokan. Saya menduga bahwa contoh seperti ini jarang terjadi dalam praktiknya.
Tipe konstruktor yang merupakan Monad:
Tentang Panah:
Bertanya di mana Arrow berada pada hierarki ini seperti menanyakan bentuk apa yang "merah". Perhatikan ketidakcocokan jenis:
tapi,
sumber
Either a
sebagai contoh untuk kasus terakhir, karena lebih mudah dimengerti.ZipList
._|_
mendiami setiap jenis dalam *, tetapi intinyaVoid
adalah Anda harus membungkuk ke belakang untuk membangun satu atau Anda telah menghancurkan nilainya. Inilah sebabnya mengapa ini bukan turunan dari Enum, Monoid, dll. Jika Anda sudah memilikinya, saya senang membiarkan Anda menumbuk mereka bersama-sama (memberi Anda aSemigroup
) tetapimempty
, tetapi saya tidak memberikan alat untuk secara eksplisit membangun nilai ketikVoid
divoid
. Anda harus memuat pistol dan mengarahkannya ke kaki Anda dan menarik pelatuknya sendiri.Gaya saya mungkin sempit oleh ponsel saya, tapi begini saja.
tidak bisa menjadi Functor. Jika ya, kita harus melakukannya
dan Bulan akan terbuat dari keju hijau.
Sementara itu
adalah functor
tetapi tidak bisa menjadi aplikatif, atau kita miliki
dan Green akan dibuat dari keju Bulan (yang sebenarnya bisa terjadi, tetapi baru nanti malam).
(Catatan tambahan:,
Void
seperti padaData.Void
datatype kosong. Jika Anda mencoba menggunakanundefined
untuk membuktikan itu adalah Monoid, saya akan gunakanunsafeCoerce
untuk membuktikan bahwa itu bukan.)Dengan gembira,
bersifat aplikatif dalam banyak hal, misalnya, seperti yang Dijkstra miliki,
tapi itu tidak bisa menjadi Monad. Untuk melihat mengapa tidak, perhatikan bahwa pengembalian harus secara konstan
Boo True
atauBoo False
, dan karenanyatidak mungkin tahan.
Oh ya, aku hampir lupa
adalah Monad. Gulung sendiri.
Pesawat untuk ditangkap ...
sumber
mempty
._|_
Saya percaya jawaban lain melewatkan beberapa contoh sederhana dan umum:
Tipe konstruktor yang merupakan Functor tetapi bukan Applicative. Contoh sederhana adalah pasangan:
Tetapi tidak ada cara bagaimana mendefinisikan
Applicative
instance -nya tanpa memaksakan pembatasan tambahanr
. Secara khusus, tidak ada cara bagaimana mendefinisikanpure :: a -> (r, a)
untuk arbitrerr
.Tipe konstruktor yang merupakan Aplikasi, tetapi bukan Monad. Contoh yang terkenal adalah ZipList . (Ini adalah
newtype
yang membungkus daftar dan memberikanApplicative
contoh berbeda untuk mereka.)fmap
didefinisikan dengan cara biasa. Tetapipure
dan<*>
didefinisikan sebagaisehingga
pure
menciptakan daftar tak terbatas dengan mengulangi nilai yang diberikan, dan<*>
ritsleting daftar fungsi dengan daftar nilai - berlaku i fungsi -th ke i elemen th. (Standar<*>
pada[]
menghasilkan semua kemungkinan kombinasi menerapkan i fungsi -th ke j elemen th.) Tetapi tidak ada cara yang masuk akal bagaimana untuk menentukan monad (lihat posting ini ).Bagaimana panah masuk ke dalam hierarki functor / applicative / monad? Lihat Idiom tidak menyadari, panah sangat teliti, monad bebas oleh Sam Lindley, Philip Wadler, Jeremy Yallop. MSFP 2008. (Mereka menyebut idiom fungsi aplikator .) Abstrak:
sumber
((,) r)
adalah functor yang bukan aplikasi; tapi ini hanya karena Anda tidak dapat umumnya mendefinisikanpure
untuk semuar
sekaligus. Oleh karena itu, ini merupakan kekhasan dari keringkasan bahasa, dalam upaya mendefinisikan koleksi fungsional aplikator (tak terbatas) dengan satu definisipure
dan<*>
; dalam pengertian ini, tampaknya tidak ada yang secara matematis mendalam tentang contoh-counter ini karena, untuk beton apa punr
,((,) r)
dapat dibuat sebagai functor aplikatif. Pertanyaan: Dapatkah Anda memikirkan functor BETON yang gagal menjadi aplikasi?Contoh yang baik untuk konstruktor tipe yang bukan functor adalah
Set
: Anda tidak dapat mengimplementasikanfmap :: (a -> b) -> f a -> f b
, karena tanpa kendala tambahanOrd b
Anda tidak dapat membangunf b
.sumber
fmap
hanyalah masalah bahasa / implementasi. Juga, dimungkinkan untukSet
memasukkan ke dalam monad kelanjutan, yang membuat monad dengan semua properti yang kita harapkan, lihat pertanyaan ini (walaupun saya tidak yakin apakah itu dapat dilakukan secara efisien).b
mungkin tidak dapat ditentukan, dalam hal ini Anda tidak dapat menentukanfmap
!Functor
turunan denganOrd
kendala, tetapi mungkin dengan definisi berbedaFunctor
atau dukungan bahasa yang lebih baik. Sebenarnya dengan ConstraintKinds adalah mungkin untuk mendefinisikan kelas tipe yang dapat ditentukan seperti ini.ord
kendala, fakta bahwa aSet
tidak dapat memuat entri rangkap berarti yangfmap
dapat mengubah konteks. Ini melanggar hukum asosiatif.Saya ingin mengusulkan pendekatan yang lebih sistematis untuk menjawab pertanyaan ini, dan juga untuk menunjukkan contoh-contoh yang tidak menggunakan trik khusus seperti nilai "bawah" atau tipe data yang tak terbatas atau semacamnya.
Kapan konstruktor tipe gagal memiliki instance kelas tipe?
Secara umum, ada dua alasan mengapa konstruktor tipe bisa gagal memiliki turunan dari kelas tipe tertentu:
Contoh jenis pertama lebih mudah daripada jenis kedua karena untuk jenis pertama, kita hanya perlu memeriksa apakah seseorang dapat mengimplementasikan suatu fungsi dengan tipe tanda tangan yang diberikan, sedangkan untuk jenis kedua, kita diharuskan membuktikan bahwa tidak ada implementasi mungkin bisa memenuhi hukum.
Contoh spesifik
Tipe konstruktor yang tidak dapat memiliki instance functor karena tipe tidak dapat diimplementasikan:
Ini adalah contrafunctortor, bukan functor, sehubungan dengan parameter tipe
a
, karenaa
dalam posisi contravarian. Tidak mungkin untuk mengimplementasikan fungsi dengan tipe tanda tangan(a -> b) -> F z a -> F z b
.Tipe konstruktor yang bukan merupakan fungsi yang sah meskipun tipe tanda tangan
fmap
dapat diimplementasikan:Aspek yang menarik dari contoh ini adalah bahwa kita dapat mengimplementasikan
fmap
tipe yang benar walaupunF
tidak mungkin menjadi functor karena digunakana
dalam posisi contravarian. Jadi implementasi yangfmap
ditunjukkan di atas ini menyesatkan - meskipun memiliki tanda tangan jenis yang benar (saya percaya ini adalah satu-satunya implementasi yang mungkin dari tanda tangan jenis itu), undang-undang functor tidak puas. Misalnya,fmap id
≠id
, karenalet (Q(f,_)) = fmap id (Q(read,"123")) in f "456"
memang123
, tetapilet (Q(f,_)) = id (Q(read,"123")) in f "456"
ada456
.Faktanya,
F
ini hanya seorang profunctor, - ia bukan functor atau contrafunctor.Functor sah yang tidak berlaku karena jenis tanda tangan
pure
tidak dapat diterapkan: mengambil monad Penulis(a, w)
dan menghapus kendala yangw
seharusnya menjadi monoid. Maka tidak mungkin untuk membangun nilai tipe(a, w)
outa
.Sebuah functor yang tidak aplikatif karena jenis tanda tangan dari
<*>
kaleng tidak dilaksanakan:data F a = Either (Int -> a) (String -> a)
.Sebuah functor yang tidak sah secara hukum meskipun metode tipe kelas dapat diimplementasikan:
Tipe konstruktor
P
adalah functor karenaa
hanya digunakan pada posisi kovarian.Satu-satunya implementasi yang mungkin dari tipe tanda tangan
<*>
adalah fungsi yang selalu mengembalikanNothing
:Tetapi implementasi ini tidak memenuhi hukum identitas untuk fungsi aplikator.
Applicative
bukanMonad
karena tanda tangan jenisbind
tidak dapat diimplementasikan.Saya tidak tahu contoh seperti itu!
Applicative
tetapi bukanMonad
karena hukum tidak dapat dipenuhi meskipun jenis tanda tanganbind
dapat diterapkan.Contoh ini telah menghasilkan sedikit diskusi, jadi aman untuk mengatakan bahwa membuktikan contoh ini dengan benar tidak mudah. Tetapi beberapa orang telah memverifikasi ini secara independen dengan metode yang berbeda. Lihat Apakah `data PoE a = Kosong | Pasangkan aa a monad? untuk diskusi tambahan.
Agak sulit untuk membuktikan bahwa tidak ada
Monad
contoh yang sah . Alasan untuk perilaku non-monadik adalah bahwa tidak ada cara alami untuk mengimplementasikanbind
ketika suatu fungsif :: a -> B b
dapat kembaliNothing
atauJust
untuk nilai yang berbedaa
.Mungkin lebih jelas untuk mempertimbangkan
Maybe (a, a, a)
, yang juga bukan monad, dan mencoba menerapkannyajoin
. Seseorang akan menemukan bahwa tidak ada cara penerapan yang masuk akal secara intuitifjoin
.Dalam kasus yang ditunjukkan oleh
???
, tampak jelas bahwa kita tidak dapat memproduksiJust (z1, z2, z3)
dengan cara yang masuk akal dan simetris dari enam nilai tipe yang berbedaa
. Kita tentu saja dapat memilih subset arbitrer dari enam nilai ini, - misalnya, selalu mengambil nonempty pertamaMaybe
- tetapi ini tidak akan memenuhi hukum monad. KembaliNothing
juga tidak akan memenuhi hukum.bind
- tetapi gagal dalam hukum identitas.Monad seperti pohon (atau "pohon dengan cabang-cabang berbentuk fungsi") didefinisikan sebagai
Ini adalah monad gratis di atas functor
f
. Bentuk data adalah pohon di mana setiap titik cabang adalah "functor-ful" dari sub pohon. Pohon biner standar akan diperoleh dengantype f a = (a, a)
.Jika kita memodifikasi struktur data ini dengan membuat juga daun dalam bentuk functor
f
, kita memperoleh apa yang saya sebut "semimonad" - ia memilikibind
yang memenuhi hukum naturalitas dan asosiasi, tetapipure
metodenya gagal dalam salah satu hukum identitas. "Semimonad adalah semigroup dalam kategori endofunctor, apa masalahnya?" Ini adalah kelas tipeBind
.Untuk mempermudah, saya mendefinisikan
join
metode alih-alihbind
:Pencangkokan cabang adalah standar, tetapi pencangkokan daun adalah non-standar dan menghasilkan a
Branch
. Ini bukan masalah bagi hukum asosiatif tetapi melanggar salah satu hukum identitas.Kapan tipe polinom memiliki turunan monad?
Tak satu pun dari functors
Maybe (a, a)
danMaybe (a, a, a)
dapat diberikanMonad
contoh yang sah , meskipun mereka jelasApplicative
.Fungsi-fungsi ini tidak memiliki trik - tidak ada
Void
atau dibottom
mana pun, tidak ada kemalasan / keketatan yang rumit, tidak ada struktur tanpa batas, dan tidak ada batasan kelas tipe. MesinApplicative
virtual benar-benar standar. Fungsireturn
danbind
dapat diterapkan untuk fungsi-fungsi ini tetapi tidak akan memenuhi hukum monad. Dengan kata lain, fungsi-fungsi ini bukan monad karena struktur spesifik tidak ada (tetapi tidak mudah untuk memahami apa yang sebenarnya hilang). Sebagai contoh, perubahan kecil pada functor dapat membuatnya menjadi monad:data Maybe a = Nothing | Just a
adalah monad. Functor serupa lainnyadata P12 a = Either a (a, a)
juga monad.Konstruksi untuk polinomial monad
Secara umum, berikut adalah beberapa konstruksi yang menghasilkan
Monad
jenis polinomial yang sah menurut hukum . Dalam semua konstruksi ini,M
adalah monad:type M a = Either c (w, a)
di manaw
ada monoidtype M a = m (Either c (w, a))
di manam
ada monad danw
monoidtype M a = (m1 a, m2 a)
di manam1
danm2
apa pun monadtype M a = Either a (m a)
dimanakahm
monad?Konstruksi pertama adalah
WriterT w (Either c)
, konstruksi kedua adalahWriterT w (EitherT c m)
. Konstruksi ketiga adalah produk bijak komponen:pure @M
didefinisikan sebagai produk bijak komponenpure @m1
danpure @m2
, danjoin @M
didefinisikan dengan menghilangkan data produk-silang (misalnyam1 (m1 a, m2 a)
dipetakanm1 (m1 a)
dengan menghilangkan bagian kedua tupel):Konstruksi keempat didefinisikan sebagai
Saya telah memeriksa bahwa keempat konstruksi menghasilkan monad yang sah.
Saya menduga bahwa tidak ada konstruksi lain untuk monad polinomial. Sebagai contoh, functor
Maybe (Either (a, a) (a, a, a, a))
tidak diperoleh melalui konstruksi ini dan tidak monadik. Namun,Either (a, a) (a, a, a)
ini monadic karena isomorfik untuk produk dari tiga monadsa
,a
danMaybe a
. Juga,Either (a,a) (a,a,a,a)
bersifat monadik karena isomorfik dengan produka
danEither a (a, a, a)
.Keempat konstruksi yang ditunjukkan di atas akan memungkinkan kami untuk mendapatkan sejumlah produk dalam jumlah berapa pun
a
, misalnyaEither (Either (a, a) (a, a, a, a)) (a, a, a, a, a))
dan sebagainya. Semua konstruktor tipe seperti itu akan memiliki (setidaknya satu)Monad
instance.Masih harus dilihat, kasus penggunaan apa yang mungkin ada untuk monad semacam itu. Masalah lain adalah bahwa
Monad
turunan yang diturunkan melalui konstruksi 1-4 pada umumnya tidak unik. Sebagai contoh, konstruktor tipetype F a = Either a (a, a)
dapat diberikanMonad
contoh dalam dua cara: dengan konstruksi 4 menggunakan monad(a, a)
, dan dengan konstruksi 3 menggunakan tipe isomorfismaEither a (a, a) = (a, Maybe a)
. Sekali lagi, menemukan kasus penggunaan untuk implementasi ini tidak segera jelas.Sebuah pertanyaan tetap - diberikan tipe data polinomial sewenang-wenang, bagaimana mengenali apakah ia memiliki
Monad
instance. Saya tidak tahu bagaimana membuktikan bahwa tidak ada konstruksi lain untuk polinomial monad. Saya tidak berpikir ada teori sejauh ini untuk menjawab pertanyaan ini.sumber
B
adalah monad. Bisakah Anda memberikan contoh tandingan terhadap ikatan iniPair x y >>= f = case (f x, f y) of (Pair x' _,Pair _ y') -> Pair x' y' ; _ -> Empty
?f
seperti yangf x
adalahEmpty
tetapif y
adalahPair
, dan pada langkah berikutnya keduanyaPair
. Saya memeriksa dengan tangan bahwa undang-undang tidak berlaku untuk implementasi ini atau untuk implementasi lainnya. Tetapi ini adalah pekerjaan yang cukup adil untuk melakukannya. Saya berharap ada cara yang lebih mudah untuk mengetahuinya!Maybe
karenaMaybe
tidak mengandung nilai yang berbedaa
untuk dikhawatirkan.Monad
instance terdiri dari fungsireturn
danbind
yang memenuhi hukum. Ada dua implementasireturn
dan 25 implementasibind
yang sesuai dengan tipe yang dibutuhkan. Anda dapat menunjukkan dengan perhitungan langsung bahwa tidak ada implementasi yang memenuhi hukum. Untuk mengurangi jumlah pekerjaan yang diperlukan, saya menggunakanjoin
alih-alihbind
dan menggunakan undang-undang identitas terlebih dahulu. Tapi ini sedikit kerjaan.Traversable
diperlukan.m (Either a (m a))
ditransformasikan menggunakanpure @m
menjadim (Either (m a) (m a))
. Lalu sepeleEither (m a) (m a) -> m a
, dan bisa kita gunakanjoin @m
. Itulah implementasi yang saya periksa hukumnya.