แปลจาก monad เป็นแอปพลิเคชัน

โอเค ฉันรู้แล้วว่าคลาสประเภท Applicative มีอะไรบ้าง และเหตุใดจึงมีประโยชน์ แต่ฉันไม่สามารถสรุปได้ว่าคุณจะใช้มันอย่างไรในตัวอย่างที่ไม่สำคัญ

พิจารณาตัวอย่าง ตัวแยกวิเคราะห์ Parsec ที่ค่อนข้างง่ายต่อไปนี้:

integer :: Parser Integer
integer = do
  many1 space
  ds <- many1 digit
  return $ read ds

ทีนี้คุณจะเขียนแบบนั้นโดยไม่ใช้อินสแตนซ์ Monad สำหรับ Parser ได้อย่างไร หลายคนอ้างว่าสิ่งนี้สามารถทำได้และเป็นความคิดที่ดี แต่ฉันไม่สามารถเข้าใจได้ว่าจะต้องทำอย่างไร


person MathematicalOrchid    schedule 27.02.2013    source แหล่งที่มา


คำตอบ (3)


integer :: Parser Integer
integer = read <$> (many1 space *> many1 digit)

Or

integer = const read <$> many1 space <*> many1 digit

ไม่ว่าคุณจะคิดว่าสิ่งใดสิ่งหนึ่งเหล่านี้อ่านง่ายกว่านั้นก็ขึ้นอยู่กับคุณ

person dave4420    schedule 27.02.2013
comment
เราต้องการละเว้นค่า (แต่ไม่ใช่ผลกระทบ) ของ many1 space และใช้ read กับค่า many1 digit (ขออภัย ฉันเพิ่งเข้ามา มันสาย ฉันเหนื่อย: ฉันเล่นเร็วและหลวมกับคำศัพท์) หากคุณจินตนาการว่า s และ d แสดงถึงค่าของ many1 space และ many1 digit ตามลำดับ ค่านั้น (โดยไม่สนใจ เอฟเฟกต์) ของ const read <$> many1 space <*> many1 digit คือ const read s d = read d - person dave4420; 01.03.2013

ฉันจะเขียน

integer :: Parser Integer
integer = read <$ many1 space <*> many1 digit

มีตัวดำเนินการสร้างพาร์เซอร์ที่เชื่อมโยงด้านซ้าย (เช่นแอปพลิเคชัน) จำนวนมาก <$>, <*>, <$, <* สิ่งที่อยู่ทางซ้ายสุดควรเป็นฟังก์ชันแท้ที่รวบรวมค่าผลลัพธ์จากค่าส่วนประกอบ สิ่งที่อยู่ทางขวาของโอเปอเรเตอร์แต่ละตัวควรเป็นตัวแยกวิเคราะห์ โดยให้ส่วนประกอบของไวยากรณ์จากซ้ายไปขวารวมกัน โอเปอเรเตอร์ที่จะใช้นั้นขึ้นอยู่กับสองตัวเลือกดังนี้

  the thing to the right is    signal  / noise
  _________________________            
  the thing to the left is \           
                            +-------------------
                    pure /  |   <$>       <$
                  a parser  |   <*>       <*

ดังนั้น เมื่อเลือก read :: String -> Integer เป็นฟังก์ชันล้วนๆ ที่จะส่งมอบซีแมนทิกส์ของพาร์เซอร์ เราก็สามารถจำแนกช่องว่างนำหน้าเป็น "สัญญาณรบกวน" และกลุ่มตัวเลขเป็น "สัญญาณ" ได้ ดังนั้น

 read <$ many1 space <*> many1 digit
 (..)    (.........)     (.........)
 pure    noise parser     |
 (.................)      |
     parser              signal parser
 (.................................)
                    parser

คุณสามารถรวมความเป็นไปได้หลายอย่างเข้าด้วยกัน

p1 <|> ... <|> pn

และแสดงความเป็นไปไม่ได้ด้วย

empty

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

person pigworker    schedule 27.02.2013
comment
ว้าว ฉันรู้เกี่ยวกับ <$ แต่ฉันจะใช้มันก็ต่อเมื่อสิ่งที่ทางด้านซ้ายเป็นค่าคงที่ และทางขวาเป็นค่าธรรมดา... ฉันไม่เคยคิดเลยว่าจะเกิดอะไรขึ้นถ้าฉันใส่ฟังก์ชันไปทางซ้าย : P เคล็ดลับดีๆ - person Niklas B.; 28.02.2013

ตัวอย่างของคุณสามารถค่อยๆ เขียนใหม่เป็นรูปแบบที่มีลักษณะคล้ายกับ Applicative ชัดเจนยิ่งขึ้น:

do
  many1 space
  ds <- many1 digit
  return $ read ds
  1. คำจำกัดความของสัญกรณ์ do:

    many1 space >> (many1 digit >>= \ds -> return $ read ds)
    
  2. คำจำกัดความของ $:

    many1 space >> (many1 digit >>= \ds -> return (read ds))
    
  3. คำจำกัดความของ .:

    many1 space >> (many1 digit >>= (return . read))
    
  4. กฎพระภิกษุที่ 3 (ความเชื่อมโยง):

    (many1 space >> many1 digit) >>= (return . read)
    
  5. คำจำกัดความของ liftM (ในรูปแบบที่ไม่ใช่ do):

    liftM read (many1 space >> many1 digit)
    

นี่คือ (หรือควรจะเป็นถ้าฉันไม่ทำผิดพลาด :)) พฤติกรรมเหมือนกันกับตัวอย่างของคุณ

ตอนนี้ หากคุณแทนที่ liftM ด้วย fmap ด้วย <$> และ >> ด้วย *> คุณจะได้รับค่า Applicative:

read <$> (many1 space *> many1 digit)

ข้อมูลนี้ใช้ได้เนื่องจากโดยทั่วไปแล้ว liftM, fmap และ <$> ควรจะเป็นคำพ้องความหมาย เช่นเดียวกับ >> และ *>

ทั้งหมดนี้ใช้งานได้และเราสามารถทำได้เนื่องจากตัวอย่างดั้งเดิมไม่ได้ใช้ผลลัพธ์ของ parser ใด ๆ เพื่อสร้าง parser ต่อไปนี้

person Matt Fenwick    schedule 01.03.2013
comment
เย็น! อีกวิธีหนึ่งในการเขียน read <$ many1 space <*> many1 digit :) ประโยคสุดท้ายมีความสำคัญมาก นั่นหมายความว่าสไตล์นี้สอดคล้องกับไวยากรณ์ที่ไม่มีบริบท และไวยากรณ์ทั่วไปมากกว่านั้นจะต้องแยกวิเคราะห์ด้วยสไตล์ monadic ใช่หรือไม่ - person Will Ness; 05.03.2013
comment
@WillNess ฉันไม่ใช่ผู้เชี่ยวชาญในเรื่องนี้ แต่ฉันเชื่อว่าเป็นเช่นนั้น - person Matt Fenwick; 05.03.2013