The Applicative
typeclass mewakili longgar monoidal functors yang melestarikan struktur monoidal Cartesian pada kategori fungsi diketik.
Dengan kata lain, diberikan kesaksian isomorfisme kanonik yang (,)
membentuk struktur monoid:
-- Implementations left to the motivated reader
assoc_fwd :: ((a, b), c) -> (a, (b, c))
assoc_bwd :: (a, (b, c)) -> ((a, b), c)
lunit_fwd :: ((), a) -> a
lunit_bwd :: a -> ((), a)
runit_fwd :: (a, ()) -> a
runit_bwd :: a -> (a, ())
Typeclass dan hukum-hukumnya dapat ditulis seperti ini:
class Functor f => Applicative f
where
zip :: (f a, f b) -> f (a, b)
husk :: () -> f ()
-- Laws:
-- assoc_fwd >>> bimap id zip >>> zip
-- =
-- bimap zip id >>> zip >>> fmap assoc_fwd
-- lunit_fwd
-- =
-- bimap husk id >>> zip >>> fmap lunit_fwd
-- runit_fwd
-- =
-- bimap id husk >>> zip >>> fmap runit_fwd
Orang mungkin bertanya-tanya seperti apa fungsi yang oplax monoidal sehubungan dengan struktur yang sama terlihat seperti:
class Functor f => OpApplicative f
where
unzip :: f (a, b) -> (f a, f b)
unhusk :: f () -> ()
-- Laws:
-- assoc_bwd <<< bimap id unzip <<< unzip
-- =
-- bimap unzip id <<< unzip <<< fmap assoc_bwd
-- lunit_bwd
-- =
-- bimap unhusk id <<< unzip <<< fmap lunit_bwd
-- runit_bwd
-- =
-- bimap id unhusk <<< unzip <<< fmap runit_bwd
Jika kita berpikir tentang tipe-tipe yang terlibat dalam definisi dan hukum, kebenaran yang mengecewakan terungkap; OpApplicative
tidak lebih spesifik daripada kendala Functor
:
instance Functor f => OpApplicative f
where
unzip fab = (fst <$> fab, snd <$> fab)
unhusk = const ()
Namun, sementara setiap Applicative
functor (benar-benar, ada Functor
) sepele OpApplicative
, belum tentu ada hubungan yang baik antara Applicative
kelemahan dan OpApplicative
oplaxities. Jadi kita dapat mencari functor monoid yang kuat dengan struktur monoid cartesian:
class (Applicative f, OpApplicative f) => StrongApplicative f
-- Laws:
-- unhusk . husk = id
-- husk . unhusk = id
-- zip . unzip = id
-- unzip . zip = id
Hukum pertama di atas adalah sepele, karena satu-satunya penghuni jenis () -> ()
ini adalah fungsi identitas ()
.
Namun, tiga undang-undang yang tersisa, dan karenanya subkelas itu sendiri, tidak sepele. Secara khusus, tidak setiap Applicative
contoh turunan dari kelas ini.
Berikut adalah beberapa Applicative
fungsi yang kami dapat nyatakan hal-hal yang sah dari StrongApplicative
:
Identity
VoidF
(->) r
(Lihat jawaban)Monoid m => (,) m
Vec (n :: Nat)
Stream
(tak terbatas)
Dan di sini ada beberapa Applicative
yang kita tidak bisa:
[]
Either e
Maybe
NonEmptyList
Pola di sini menunjukkan bahwa StrongApplicative
kelas dalam arti tertentu adalah FixedSize
kelas, di mana "ukuran tetap" * berarti bahwa multiplisitas ** penduduk a
dalam suatu penduduk f a
adalah tetap.
Ini dapat dinyatakan sebagai dua dugaan:
- Setiap
Applicative
mewakili wadah "ukuran tetap" elemen dari argumen jenisnya adalah turunan dariStrongApplicative
- Tidak ada contoh
StrongApplicative
ada di mana jumlah kejadiana
dapat bervariasi
Adakah yang bisa memikirkan contoh tandingan yang menyangkal dugaan ini, atau beberapa alasan meyakinkan yang menunjukkan mengapa itu benar atau salah?
* Saya menyadari bahwa saya belum mendefinisikan kata sifat "ukuran tetap" dengan benar. Sayangnya tugasnya agak melingkar. Saya tidak tahu deskripsi formal dari wadah "ukuran tetap", dan saya mencoba untuk membuat satu. StrongApplicative
adalah upaya terbaik saya sejauh ini.
Untuk mengevaluasi apakah ini definisi yang baik, saya perlu membandingkannya. Diberikan beberapa definisi formal / informal tentang apa artinya bagi functor untuk memiliki ukuran atau multiplisitas yang diberikan sehubungan dengan penduduk dari argumen tipenya, pertanyaannya adalah apakah keberadaan sebuah StrongApplicative
instance secara tepat membedakan functors dari fixed dan berbagai ukuran.
Karena tidak mengetahui definisi formal yang ada, saya memohon intuisi dalam penggunaan istilah "ukuran tetap". Namun jika seseorang sudah mengetahui formalisme yang ada untuk ukuran functor dan dapat membandingkannya StrongApplicative
, itu jauh lebih baik.
** Dengan "multiplisitas" Saya mengacu pada pengertian longgar untuk "berapa banyak" elemen sewenang-wenang dari tipe parameter functor yang terjadi pada penghuni jenis codomain functor. Ini tanpa memperhatikan tipe spesifik dari functor diterapkan, dan karenanya tanpa memperhatikan penghuni spesifik dari tipe parameter.
Tidak tepatnya tentang hal ini telah menyebabkan beberapa kebingungan dalam komentar, jadi inilah beberapa contoh dari apa yang saya anggap ukuran / multiplisitas berbagai fungsi menjadi:
VoidF
: diperbaiki, 0Identity
: diperbaiki, 1Maybe
: variabel, minimum 0, maksimum 1[]
: variabel, minimum 0, maksimum tak terbatasNonEmptyList
: variabel, minimum 1, maksimum tak terbatasStream
: diperbaiki, tak terbatasMonoid m => (,) m
: diperbaiki, 1data Pair a = Pair a a
: diperbaiki, 2Either x
: variabel, minimum 0, maksimum 1data Strange a = L a | R a
: diperbaiki, 1
sumber
(->) r
is dan mereka isomorfik dengan cara yang benar.(->) r
; Anda memerlukan komponen isomorfisma untuk mempertahankan struktur aplikasi yang kuat. Untuk beberapa alasan,Representable
typeclass di Haskell memilikitabulate . return = return
hukum misterius (yang bahkan tidak masuk akal untuk fungsi non monadik), tetapi memberi kita 1/4 dari kondisi yang perlu kita katakantabulate
danzip
merupakan morfisme dari kategori monoids yang cocok. . 3 lainnya adalah undang-undang tambahan yang harus Anda tuntut.tabulate
danindex
merupakan morfisme dari kategori yang cocok ..."return
bukan masalah serius.cotraverse getConst . Const
adalah implementasi default untukreturn
/pure
dalam halDistributive
, dan, karena distribusi / keterwakilan memiliki bentuk tetap, implementasi itu unik.Jawaban:
Saya tidak yakin tentang dugaan pertama itu, dan berdasarkan diskusi dengan @AsadSaeeduddin kemungkinan sulit untuk dibuktikan, tetapi dugaan kedua benar. Untuk melihat alasannya, pertimbangkan
StrongApplicative
hukumhusk . unhusk == id
; yaitu, untuk semuax :: f ()
,husk (unhusk x) == x
. Namun dalam Haskell,unhusk == const ()
sehingga hukum yang setara dengan mengatakan untuk semuax :: f ()
,husk () == x
. Tetapi ini pada gilirannya menyiratkan bahwa hanya ada satu nilai tipe yang berbedaf ()
: jika ada dua nilaix, y :: f ()
, makax == husk ()
danhusk () == y
, begitux == y
. Tetapi jika hanya ada satuf ()
nilai yang mungkin , makaf
harus dari bentuk tetap. (misalnya untukdata Pair a = Pair a a
, hanya ada satu nilai tipePair ()
, makhluk iniPair () ()
, tetapi ada beberapa nilai tipeMaybe ()
atau[()]
.) Jadihusk . unhusk == id
menyiratkan bahwaf
harus berbentuk tetap.sumber
f ()
" menyiratkan "jumlah kemunculana
tidak dapat bervariasi" dengan adanya GADT dan barang mewah?a
tidak dapat bervariasi” bukanlah kondisi yang cukup untuk sebuahStrongApplicative
instance; misalnya,data Writer w a = Writer (w,a)
memiliki multiplisitas yang tidak beragama
, tetapi bukan aStrongApplicative
. Anda benar-benar membutuhkan bentuk functor agar tidak berubah-ubah, yang saya yakin merupakan konsekuensi darif ()
menjadi seorang lajang.f ()
" menyiratkan "jumlah kejadiana
tidak dapat bervariasi". Saya keberatan bahwa langkah terakhir dari argumen itu tidak jelas benar; misalnya mempertimbangkandata Weird a where One :: a -> Weird a; None :: Weird Bool
. Ada nilai tipe yangWeird ()
berbeda, tetapi konstruktor yang berbeda memiliki jumlaha
s yang berbeda-beda . (Ini bukan contoh tandingan penuh di sini karenaFunctor
sulit, tetapi bagaimana kita tahu itu tidak dapat diperbaiki?)Weird ()
merupakan singleton tetapi tidak dalam bentuk yang pasti. TapiWeird
bukan aFunctor
, jadi itu tidak mungkinStrongApplicative
. Saya kira dugaan yang relevan adalah: jikaf
aFunctor
, apakahf ()
menjadi lajang menyiratkan bahwa ituf
adalah bentuk tetap ? Saya sangat curiga ini benar, tetapi seperti yang Anda perhatikan, saya belum benar-benar memiliki bukti.Kami dapat menjawab setidaknya satu dari pertanyaan ini dalam negatif:
Sebenarnya salah satu contoh halal
StrongApplicative
dalam pertanyaan asli salah. Pelamar penulisMonoid => (,) m
tidakStrongApplicative
, karena misalnyahusk $ unhusk $ ("foo", ()) == ("", ()) /= ("foo", ())
.Demikian pula, contoh wadah ukuran tetap:
dari multiplisitas tetap 1, bukan aplikatif yang kuat, karena jika kita mendefinisikan
husk = Left
kemudianhusk $ unhusk $ Right () /= Right ()
, dan sebaliknya. Cara yang setara untuk melihat ini adalah bahwa ini hanya aplikasi penulis untuk monoid pilihan AndaBool
.Jadi ada pelamar "ukuran tetap" yang tidak
StrongApplicative
. Apakah semuaStrongApplicative
ukuran tetap masih harus dilihat.sumber
Mari kita ambil functors yang dapat direpresentasikan sebagai definisi kami tentang "wadah ukuran tetap":
Real
Representable
memiliki beberapa hukum dan superclasses, tetapi untuk keperluan jawaban ini, kita sebenarnya hanya membutuhkan dua properti:(Oke, kita juga perlu taat hukum
instance StrongApplicative ((->) r)
. Mudah sekali, kamu sudah setuju itu ada.)Jika kita mengambil definisi itu, maka saya dapat mengkonfirmasi dugaan 1:
adalah benar. Begini caranya:
Ada banyak hukum untuk dibuktikan, tapi saya akan fokus hanya pada Big Four yang
StrongApplicative
menambahkan - Anda mungkin sudah percaya yang memimpin untuk ,Applicative
danOpApplicative
jika Anda tidak, buktinya terlihat seperti yang di bawah ini ( yang pada gilirannya terlihat sangat mirip satu sama lain). Untuk kejelasan, saya akan menggunakanzipf
,huskf
, dll untuk contoh fungsi, danzipr
,huskr
, dll untuk contoh representable, sehingga Anda dapat melacak yang mana. (Dan agar mudah untuk memverifikasi bahwa kita tidak mengambil hal yang kita coba buktikan sebagai asumsi! Tidak apa-apa untuk digunakanunhuskf . huskf = id
ketika membuktikanunhuskr . huskr = id
, tetapi akan salah untuk mengasumsikanunhuskr . huskr = id
dalam bukti yang sama.)Bukti dari setiap hukum pada dasarnya menghasilkan cara yang sama: membuka gulungan definisi, menjatuhkan isomorfisme yang
Representable
memberi Anda, kemudian menggunakan hukum analog untuk fungsi.sumber
instance StrongApplicative f => Representable f where type Rep f = forall x. f x -> x
.index
gampang. Saya belum mengerjakan triknyatabulate
, tapi sepertinya menggoda.StrongApplicative
contoh yang sama juga, tetapi tidak dapat membuktikan hukum. Selamat atas jawabannya! Saya mencoba untuk melakukanRepresentable
instance juga diberikanStrongApplicative
, tetapi tidak bisa memikirkanRep
jenis yang baik - saya ingin tahu, bagaimana Andaforall x. f x -> x
mencapai ini?forall x. f x -> x
adalah fungsi-fungsi yang memilih lubang dan mengembalikan nilai dalam lubang itu. (Dan, sambil berpikir tentang cara menerapkantabulate
, saya telah mengajukan keberatan atas jenisnyaunhusk
; lihat komentar pada pertanyaan itu sendiri untuk perinciannya.)forall x. f x -> x
akan berhasilRep
. Alasan saya adalah bahwa, dengan menggunakan iniRep
, Anda dapat menulisindex
untuk jenis apa pun , bukan hanya tipeStrongApplicative
- jadi saya menduga ituforall x. f x -> x
mungkin terlalu umum.