Bagaimana sequenceA bekerja pada daftar pasangan?
Putar pertanyaan ini . Secara intuitif saya telah memahami apa yang sequenceAdilakukan dalam kasus penggunaan itu, tetapi tidak bagaimana / mengapa hal itu bekerja seperti itu.
Jadi intinya adalah pertanyaan ini: bagaimana cara sequenceAkerjanya dalam kasus berikut?
> sequenceA [("a",1),("b",2),("c",3)]
("abc",[1,2,3])
saya melihat bahwa
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
jadi dalam usecase di atas Traversableis [], dan Applicative, karena (,)adalah konstruktor tipe biner, is (,) a, yang berarti bahwa pasangan diambil sebagai functor aplikatif pada sndbidangnya. Dan ini berjalan bersama daftar yang berakhir di sndhasil. Jadi kita beralih dari daftar pasangan menjadi pasangan dengan daftar di bidang kedua.
Tapi dari mana "abc"asalnya? Maksud saya, saya tahu bahwa ini adalah rangkaian dari fstsemua pasangan, tapi saya tidak tahu apakah itu melalui ++atau melalui concatdaftar fsts. Tampaknya tidak ada sequenceAtanda tangan yang menegaskan bahwa fstpasangan dapat digabungkan.
Tetap saja asumsi itu harus digunakan di suatu tempat. Memang, berikut ini gagal
sequenceA [('a',1),('b',2),('c',3)]
Jawaban
Di Haskell, instance kelas tipe untuk suatu tipe bisa "bersyarat" pada keberadaan instance kelas tipe lain untuk bagian dari tipe tersebut. Tidak semua konstruktor tipe formulir ((,) a)adalah instance Applicative, tetapi hanya konstruktor yang atipenya memiliki Monoidinstance.
Batasan yang diperlukan ini muncul sebelum =>di Haddock instance, seperti ini:
Monoid a => Applicative ((,) a)
Mengapa Monoidcontoh diperlukan? Untuk satu, pureuntuk ((,) a)kebutuhan mewujudkan anilai dari udara tipis untuk dimasukkan ke dalam elemen pertama tupel. memptyuntuk tipe yang amelakukan pekerjaan itu.
Mungkin ada rantai kendala yang diperlukan yang memiliki kedalaman beberapa level. Misalnya, mengapa berikut ini berhasil?
ghci> import Datta.Function ((&)) -- flipped application
ghci> [(id :: String -> String, 2 :: Int), (\x -> x ++ x, 1)] & sequenceA & fst $ "foo"
"foofoofoo"
Di sini komponen pertama adalah sebuah fungsi. Seperti sebelumnya, harus memiliki Monoidcontoh sequenceAagar berfungsi. Tapi kapan tipe a -> ba Monoid? Melihat Haddock, kami menemukan:
Monoid b => Monoid (a -> b)
Artinya, fungsi adalah Monoids ketika tipe kembalian (di sini String) adalah a Monoid.
Sebenarnya, ada contoh lain Monoid untuk fungsi yang tersedia melalui Endotipe baru. Merupakan hal yang umum untuk menggunakan newtypes untuk memilih contoh mana yang akan digunakan untuk operasi tertentu, meskipun itu membutuhkan sejumlah pembungkusan dan pembongkaran.
Itu menggunakan mappend. The Applicativecontoh menggunakan terlihat seperti ini:
instance Monoid a => Applicative ((,) a) where
pure x = (mempty, x)
(af, f) <*> (ax, x) = (mappend af ax, f x)