Синтаксис <* в Haskell - PullRequest
       37

Синтаксис <* в Haskell

0 голосов
/ 15 февраля 2020

Мне дали следующий код

 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)

Я знаю, что ws-парсер удаляет начальные пробелы. Но мне нужно объяснение, как именно это делается. Я не понимаю синтаксис <* (знаю <*>). Может ли кто-нибудь помочь мне понять синтаксис и почему он работает?

1 Ответ

1 голос
/ 15 февраля 2020

Не бойся! Это просто, когда мы go по маленьким шагам и видим, куда нас это приведет. В следующий раз попробуйте сделать это самостоятельно.

(<*) = liftA2 const и liftA2 f x = (<*>) (fmap f x), поэтому

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) ]

(с пометкой Applicative Do) ; чтобы получить представление о том, что это делает. Аппликативные L aws перечислены и по вышеуказанной ссылке.)

Так что он делает то, что делает many (satisfy isSpace), за исключением того, что вычисленное значение, которое он возвращает, всегда ().

В чистых функциях f a = () полностью игнорирует свой второй аргумент. Мы могли бы назвать это как f (1 / 0), и это не волновало бы. Но Applicative Functors express вычислений и <*> объединяет вычисления, полностью известные до объединения, так что каждый из них получает выполненных , независимо от того, используется ли его вычисленное значение позже или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...