简体   繁体   中英

The <* syntax in Haskell

I'm given the following code

 newtype Parser a = Parser { parse :: String -> Maybe (a,String) }

   instance Applicative Parser where
   pure a = Parser $ \s -> Just (a,s)
   f <*> a = Parser $ \s ->
     case parse f s of
       Just (g,s') -> parse (fmap g a) s'
       Nothing -> Nothing

    instance Alternative Parser where
      empty = Parser $ \s -> Nothing
      l <|> r = Parser $ \s -> parse l s <|> parse r s

    satisfy :: (Char -> Bool) -> Parser Char
    satisfy p = Parser f
       where f [] = Nothing
             f (x:xs) = if p x then Just (x,xs) else Nothing

    ws :: Parser ()
    ws = pure () <* many (satisfy isSpace)

I know that ws parser removes leading spaces. But I need an explanation how exactly this is done. I don't understand the <* syntax ( I know <*> ). Can some help me understand the syntax and why it is working ?

No fear! It's easy, when we go by small steps , and see where it leads us. Next time, try doing it yourself.

(<*) = liftA2 const and liftA2 fx = (<*>) (fmap fx) , so

ws :: Parser ()
ws = pure () <* many (satisfy isSpace) 
     = {- (<*) = liftA2 const -}
     liftA2 const (pure ()) (many $ satisfy isSpace) 
     = {- liftA2 f x = (<*>) (fmap f x) -}
     fmap const (pure ()) <*> many (satisfy isSpace)
     = {- by Applicative laws -}
     (pure const <*> pure ()) <*> many (satisfy isSpace)
     = {- by homomorphism law of Applicatives -}
     pure (const ()) <*> many (satisfy isSpace)
     = {- with Applicative Do -}
     do { f <- pure (const ())
        ; r <- many (satisfy isSpace)
        ; pure (f r) }
     = {- by Law of `pure` being the identity, i.e. no-op, effects-wise -}
     do { let f = const ()
        ; r <- many (satisfy isSpace)
        ; pure (f r) }
     = {- by substitution -}
     do { r <- many (satisfy isSpace)
        ; pure (const () r) }
     =
     do { _ <- many (satisfy isSpace)
        ; pure () }
     =
     do { many (satisfy isSpace)
        ; pure () }
     = {- Monad Comprehension illustration -}
     [ () | _ <- many (satisfy isSpace) ]

(with the Applicative Do notation; to get the feeling for what this does. The Applicative Laws are enumerated at the above link as well.)

So it does what many (satisfy isSpace) does, except the computed value it returns is always () .

In pure functions, fa = () would completely ignore its second argument. We could call it as f (1 / 0) and it wouldn't care. But Applicative Functors express computations, and <*> combines computations fully known prior to the combination so that each one gets performed , whether its computed value is later used or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM