Kebutuhan akan aplikasi murni

19

Saya sedang belajar Aplikasi Haskell. Sepertinya saya (saya mungkin salah) bahwa purefungsi ini tidak benar-benar diperlukan, misalnya:

pure (+) <*> [1,2,3] <*> [3,4,5]

dapat ditulis sebagai

(+) <$> [1,2,3] <*> [3,4,5]

Adakah yang bisa menjelaskan manfaat yang diberikan purefungsi tersebut daripada pemetaan eksplisit fmap?

Gil Shafriri
sumber
1
Anda benar - pure f <*> xpersis sama dengan fmap f x. Saya yakin ada beberapa alasan mengapa puredisertakan Applicative, tetapi saya tidak sepenuhnya yakin mengapa.
bradrn
4
Saya tidak punya waktu untuk jawaban, dan tidak yakin ini akan membuat jawaban yang baik atau lengkap, tetapi satu pengamatan: purememungkinkan seseorang untuk menggunakan, baik, nilai "murni" dalam perhitungan Applicative. Sementara, seperti yang Anda amati dengan benar, pure f <*> xsama dengan f <$> x, tidak ada yang setara untuk, katakanlah f <*> x <*> pure y <*> z,. (Setidaknya saya tidak berpikir begitu.)
Robin Zigmond
3
Sebagai pembenaran lain, yang lebih teoretis, - ada formulasi alternatif yang terkait erat dengan Monoidkelas penting - di mana puresesuai dengan Monoidelemen identitas. (Ini menunjukkan bahwa Applicativetanpa purebisa menarik, karena Semigroup- yang merupakan Monoidtanpa harus memiliki identitas - masih digunakan. Sebenarnya, sekarang saya berpikir tentang hal itu, saya ingat PureScript memiliki purekelas "Applicative without " yang persis seperti itu , walaupun saya tidak tau untuk apa itu digunakan.)
Robin Zigmond
2
@RobinZigmond fmap (\f' x' z' -> f' x' y z') f <*> x <*> z, saya pikir. Idenya dalam Applicativedokumentasi sebagai hukum "pertukaran".
HTNW
3
@RobinZigmond Applicativetanpa pureada Applydari semigroupoids .
duplode

Jawaban:

8

Saya berada di ujung kompetensi saya di sini, jadi jangan anggap ini terlalu banyak, tetapi terlalu lama untuk berkomentar.

Mungkin ada alasan praktis untuk dimasukkan ke puredalam kelas tipe, tetapi banyak abstraksi Haskell berasal dari dasar-dasar teoretis, dan saya percaya itulah yang terjadi Applicativejuga. Seperti yang dikatakan dalam dokumentasi, ini adalah fungsi monoid lemah yang kuat (lihat https://cstheory.stackexchange.com/q/12412/56098 untuk elaborasi). Saya kira itu pureberfungsi sebagai identitas , seperti returnhalnya untuk Monad(yang merupakan monoid dalam kategori endofunctors ).

Pertimbangkan puredan liftA2:

pure :: a -> f a
liftA2 :: (a -> b -> c) -> f a -> f b -> f c

Jika Anda sedikit menyipit, Anda mungkin bisa membayangkan bahwa itu liftA2adalah operasi biner, yang juga merupakan apa yang dinyatakan oleh dokumentasi:

Angkat fungsi biner ke tindakan.

pureMaka, adalah identitas yang sesuai.

Mark Seemann
sumber
6
Persis. Applicativetanpa pureakan menjadi, hm, functor semigroupal daripada yang monoid.
leftaroundabout
20

fmaptidak selalu memotongnya. Secara khusus, pureadalah apa yang memungkinkan Anda memperkenalkan f(di mana fadalah Applicative) ketika Anda belum memilikinya. Contoh yang bagus adalah

sequence :: Applicative f => [f a] -> f [a]

Dibutuhkan daftar "tindakan" yang menghasilkan nilai dan mengubahnya menjadi tindakan yang menghasilkan daftar nilai. Apa yang terjadi ketika tidak ada tindakan dalam daftar? Satu-satunya hasil yang waras adalah tindakan yang tidak menghasilkan nilai:

sequence [] = pure [] -- no way to express this with an fmap
-- for completeness
sequence ((:) x xs) = (:) <$> x <*> sequence xs

Jika tidak pure, Anda harus meminta daftar tindakan kosong. Anda pasti bisa membuatnya bekerja, tetapi itu seperti berbicara tentang penambahan tanpa menyebutkan 0 atau perkalian tanpa 1 (seperti yang orang lain katakan, karena Applicatives bersifat monoid). Anda akan berulang kali mengalami kasus tepi yang mudah dipecahkan, puretetapi harus diselesaikan dengan pembatasan aneh pada input Anda dan bantuan band lainnya.

HTNW
sumber