ความจำเป็นสำหรับการบริสุทธิ์ในการประยุกต์ใช้


19

ฉันกำลังเรียนผู้สมัครของ Haskell ดูเหมือนว่าฉัน (ฉันอาจผิด) ว่าpureฟังก์ชั่นไม่จำเป็นจริงๆตัวอย่างเช่น:

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

สามารถเขียนเป็น

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

บางคนสามารถอธิบายถึงประโยชน์ที่pureฟังก์ชั่นมอบให้เหนือการทำแผนที่อย่างชัดเจนด้วยfmapหรือไม่?


1
คุณถูกต้อง - pure f <*> xเหมือนกันfmap f xทุกประการ ฉันแน่ใจว่ามีเหตุผลบางอย่างที่pureรวมอยู่ในApplicativeแต่ฉันไม่แน่ใจว่าทำไม
bradrn

4
ฉันไม่มีเวลาสำหรับคำตอบและไม่เชื่อว่าสิ่งนี้จะทำให้ดีหรือสมบูรณ์อย่างไรก็ตามการสังเกตเพียงอย่างเดียว: pureอนุญาตให้ใช้ค่าดี ​​"บริสุทธิ์" ในการคำนวณเชิงประยุกต์ ในขณะที่คุณได้อย่างถูกต้องสังเกตpure f <*> xเป็นเช่นเดียวกับไม่มีเทียบเท่าดังกล่าวสำหรับการพูดf <$> x f <*> x <*> pure y <*> z(อย่างน้อยฉันก็ไม่คิดอย่างนั้น)
Robin Zigmond

3
อีกเหตุผลหนึ่งที่สมเหตุสมผลมากกว่านั้นคือมีสูตรทางเลือกที่เกี่ยวข้องกับMonoidคลาสที่สำคัญซึ่งpureสอดคล้องกับMonoidองค์ประกอบตัวตนของ (สิ่งนี้ชี้ให้เห็นว่าApplicativeไม่pureน่าสนใจเพราะSemigroup- ซึ่งMonoidยังคงมีการระบุตัวตน - ยังคงถูกใช้จริง ๆ แล้วตอนนี้ฉันคิดเกี่ยวกับมันฉันดูเหมือนจะจำได้ว่า PureScript มีคลาส "Applicative ปราศจากpure" แม้ว่าฉันจะไม่ ไม่รู้ว่ามันใช้ทำอะไร)
Robin Zigmond

2
@ RobinZigmond fmap (\f' x' z' -> f' x' y z') f <*> x <*> zฉันคิดว่า แนวคิดนี้อยู่ในApplicativeเอกสารตามกฎหมายของ "การแลกเปลี่ยน"
HTNW

3
@RobinZigmond Applicativeโดยไม่ต้องpureอยู่ในฐานะApplyจาก semigroupoids
duplode

คำตอบ:


8

ฉันอยู่ที่ความสามารถของฉันที่นี่ดังนั้นอย่าใช้สิ่งนี้มากไปกว่านี้ แต่มันนานเกินไปสำหรับความคิดเห็น

อาจมีเหตุผลในทางปฏิบัติที่จะรวมpureไว้ในคลาสประเภท แต่ abstractions Haskell จำนวนมากได้มาจากรากฐานทางทฤษฎีและฉันเชื่อว่าApplicativeเป็นเช่นนั้น ดังที่เอกสารระบุว่ามันเป็นfunctor loid monoidal ที่แข็งแกร่ง (ดูที่https://cstheory.stackexchange.com/q/12412/56098สำหรับการทำอย่างละเอียด) ฉันคิดว่ามันpureทำหน้าที่เป็นตัวตนเหมือนreturnทำเพื่อMonad(ซึ่งเป็นmonoid ในหมวดหมู่ของ endofunctors )

พิจารณาpureและliftA2:

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

หากคุณเหลื่อมกันเล็กน้อยคุณอาจจินตนาการได้ว่าliftA2เป็นการดำเนินการแบบไบนารีซึ่งเป็นสิ่งที่เอกสารระบุไว้:

ยกฟังก์ชั่นไบนารีให้เป็นการกระทำ

pureจากนั้นเป็นตัวตนที่สอดคล้องกัน


6
เผง Applicativeโดยไม่pureต้องเป็น, hm, semigroupal functor แทนที่จะเป็น monoidal
leftaroundabout

20

fmapไม่ได้ตัดมันเสมอไป โดยเฉพาะอย่างยิ่งpureคือสิ่งที่ช่วยให้คุณสามารถแนะนำf(ที่fเป็นApplicative) เมื่อคุณไม่ได้มีมัน ตัวอย่างที่ดีคือ

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

ใช้รายการของ "การกระทำ" ที่สร้างคุณค่าและเปลี่ยนเป็นการดำเนินการที่สร้างรายการของค่า จะเกิดอะไรขึ้นเมื่อไม่มีการดำเนินการในรายการ ผลลัพธ์สติอย่างเดียวคือการกระทำที่ไม่มีค่า:

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

หากคุณไม่มีpureคุณจะถูกบังคับให้ต้องมีรายการการกระทำที่ไม่เกี่ยวข้อง คุณสามารถทำให้มันใช้งานได้อย่างแน่นอน แต่มันก็เหมือนกับการพูดถึงการเติมโดยไม่ต้องพูดถึง 0 หรือการคูณโดยไม่มี 1 (อย่างที่คนอื่น ๆ พูดกันเพราะApplicatives เป็น monoidal) คุณจะพบกับกรณีที่เกิดขึ้นซ้ำ ๆ ซึ่งจะสามารถแก้ไขได้อย่างง่ายดายด้วยpureแต่จะต้องได้รับการแก้ไขโดยข้อ จำกัด แปลก ๆ เกี่ยวกับอินพุตและเครื่องช่วยอื่น ๆ ของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.