{-|
Module      : Options.OptStream.Classes
Copyright   : (c) Dan Shved, 2022
License     : BSD-3
Maintainer  : danshved@gmail.com
Stability   : experimental

This module contains the 'SelectiveParser' typeclass. Selective parsers can be
composed in many ways, notably using sequential application '<*>' as well as
parallel application '<#>', which makes them /twice applicative/. See the
typeclass documentation for more details.

Normally you shouldn't need to import this module as it is re-exported by
"Options.OptStream".
-}
module Options.OptStream.Classes
  ( -- * Twice applicative parsers
    SelectiveParser(..)
  , orElse
  , applyMany
  , applySome
  , (<#)
  , (#>)
  , (<##>)
  , (<-#)
  , (-#>)
  , (<-##>)
  , (<#-)
  , (#->)
  , (<##->)

    -- * Functors and Applicatives with failure
  , FunctorFail(fmapOrFail)
  , fmapOrFailM
  , (<$?>)
  , (<&?>)
  , ApplicativeFail(failA)
  )
where

import Control.Applicative hiding (some, many)
import Control.Monad.Fail
import Data.Functor
import Prelude hiding (fail)


-- * FunctorFail

-- | A functor with failure. Instances are expected to satisfy the laws:
--
-- Coordinated with 'fmap':
--
-- prop> fmapOrFail (Right . f) = fmap f
--
-- Composition:
--
-- prop> fmapOrFail f . fmapOrFail g = fmapOrFail (g >=> f)
--
-- Additionally, if @f@ is a 'MonadFail', it is expected that failure is the
-- same as the monadic 'fail':
--
-- prop> fmapOrFail Left (return err) = fail err
class Functor f => FunctorFail f where
  -- | Like 'fmap' but with a possibility for failure. This applies a function
  -- of type @(a -> 'Either' 'String' b)@ to a value of type @f a@. If the
  -- function returns a 'Left', this represents failure, with the 'String'
  -- being a message describing the nature of the failure. In this case the
  -- resulting value of type @f b@ should encapsulate this failure.
  --
  -- In command line parsing this is used by functions like
  -- 'Options.OptStream.paramRead' to produce an unrecoverable failure when a
  -- parameter cannot be parsed e.g. as an integer.
  fmapOrFail :: (a -> Either String b) -> f a -> f b

-- | Like 'Control.Monad.liftM' but with a possibility for failure. Suitable as
-- a drop-in implementation of 'fmapOrFail' for monads.
fmapOrFailM :: MonadFail f => (a -> Either String b) -> f a -> f b
fmapOrFailM :: (a -> Either String b) -> f a -> f b
fmapOrFailM a -> Either String b
f f a
a = (String -> f b) -> (b -> f b) -> Either String b -> f b
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> f b
forall (m :: * -> *) a. MonadFail m => String -> m a
fail b -> f b
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String b -> f b) -> (a -> Either String b) -> a -> f b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Either String b
f (a -> f b) -> f a -> f b
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< f a
a

infixl 4 <$?>
infixl 1 <&?>

-- | Operator form of 'fmapOrFail'. Provided for convenience.
(<$?>) :: FunctorFail f => (a -> Either String b) -> f a -> f b
<$?> :: (a -> Either String b) -> f a -> f b
(<$?>) = (a -> Either String b) -> f a -> f b
forall (f :: * -> *) a b.
FunctorFail f =>
(a -> Either String b) -> f a -> f b
fmapOrFail

-- | A version '<$?>' with the arguments flipped. Provided for convenience.
(<&?>) :: FunctorFail f => f a -> (a -> Either String b) -> f b
<&?> :: f a -> (a -> Either String b) -> f b
(<&?>) = ((a -> Either String b) -> f a -> f b)
-> f a -> (a -> Either String b) -> f b
forall a b c. (a -> b -> c) -> b -> a -> c
flip (a -> Either String b) -> f a -> f b
forall (f :: * -> *) a b.
FunctorFail f =>
(a -> Either String b) -> f a -> f b
(<$?>)


-- * ApplicativeFail

-- | An 'Applicative' that is also a 'FunctorFail'. Instances are expected to
-- satisfy the law:
--
-- prop> failA err = fmapOrFail Left (pure err)
--
-- This is also the default implementation of 'failA'.
class (Applicative f, FunctorFail f) => ApplicativeFail f where
  -- | Unconditional failure.
  failA :: String -> f a
  failA = (String -> Either String a) -> f String -> f a
forall (f :: * -> *) a b.
FunctorFail f =>
(a -> Either String b) -> f a -> f b
fmapOrFail String -> Either String a
forall a b. a -> Either a b
Left (f String -> f a) -> (String -> f String) -> String -> f a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> f String
forall (f :: * -> *) a. Applicative f => a -> f a
pure


-- * SelectiveParser

infixl 4 <#>
infixl 4 <#
infixl 4  #>
infixl 4 <##>

infixl 4 <-#>
infixl 4 <-#
infixl 4  -#>
infixl 4 <-##>

infixl 4 <#->
infixl 4 <#-
infixl 4  #->
infixl 4 <##->

infixl 3 <-|>
infixl 3 <|->

-- | A type @p@ is a 'SelectiveParser' if it offers functions '<#>', '<-#>',
-- '<#->', '<-|>', '<|->', 'eof', standard 'Applicative' functions 'pure' and
-- '<*>', and 'Alternative' functions 'empty' and '<|>'.
--
-- A selective parser handles a stream of /tokens/ of some kind. In case of
-- 'Options.OptStream.Parser' and 'Options.OptStream.RawParser', there are two
-- kinds of tokens: command line arguments and short flags (which are
-- characters inside command line arguments starting with one @-@). Common to
-- all selective parsers is also a special EOF token that is received at the
-- end of the stream.
--
-- A selective parser looks at each token, including EOF, and makes one of
-- these decisions:
--
--  * /Skip/ the token, in which case the token may be consumed by a different
--  parser. Hence the name /selective parser/: a parser only handles part of
--  the stream and skips the rest.
--
--  * /Consume/ the token, in which case there are generally two subchoices:
--
--      - Finish the parse (and return a value of type @a@, or maybe an
--      error).
--
--      - Continue the parse, i.e. keep looking at more tokens. Not an option
--      when handling EOF.
--
--
-- ==== Applicative
--
-- The meaning of 'Applicative' functions for selective parsers:
--
-- [@'pure' a@]: A parser that finishes immediately before looking at any tokens
-- and produces the value @a@.
--
-- [@f '<*>' x@]: Sequential application. The left hand side parser @f@ runs
-- first until it finishes and produces a value of type @(a -> b)@. Then the
-- right hand side parser @x@ starts running and looking at the remainder of
-- the stream. Once @x@ has finished and produced a value of type @a@, the
-- results of @f@ and @x@ are combined into a final value of type @b@.
--
--
-- ==== Alternative
--
-- [@'empty'@]:  A parser that skips all tokens, including EOF, and never
-- finishes.
--
-- [@x '<|>' y@]:  Alternative. The combined parser looks at each token and
-- determines if either of the subparsers wants to consume it (with @x@ having
-- priority over @y@). When (say) @x@ has consumed the first token, @y@ is
-- terminated, and @x@ gets to look at the rest of the stream. This implies
-- that there is no backtracking. Once either @x@ or @y@ has cosnumed a token,
-- the decision has been made and cannot be reversed.
--
-- [@many@, @some@, @optional@]:  These functions from "Control.Applicative"
-- use 'pure' as a fallback alternative. This doesn't work for selective
-- parsers (see 'orElse'), so this module provides its own replacements with
-- the same names: 'Options.OptStream.Classes.many',
-- 'Options.OptStream.Classes.some', 'Options.OptStream.Classes.optional'.
class Alternative p => SelectiveParser p where
  -- | Parallel application. This runs two parsers in parallel. For each input
  -- token, the left hand side (LHS) parser looks at it first. If the LHS
  -- parser skips the token, the right hand side (RHS) parser gets a chance to
  -- look at it too. Once both the LHS and RHS parsers have finished and
  -- produced results of type @(a -> b)@ and @a@ respectively, the compound
  -- parser also finishes and produces a combined result of type @b@.
  --
  -- Together with the sequential application '<*>' this operation makes
  -- selective parsers "twice applicative".
  (<#>) :: p (a -> b) -> p a -> p b

  -- | Left-interruptive application. This starts out in the same way as '<#>':
  -- each token is presented to the left hand side (LHS) parser first, then to
  -- the right hand side (RHS) parser if the LHS one has skipped it. However,
  -- as soon as the RHS parser has consumed a token, the LHS parser is
  -- terminated.
  --
  -- The LHS parser is terminated gracefully (it looks to the LHS parser as if
  -- it received EOF). The LHS result is stored, and the RHS parser continues
  -- to run alone. When the RHS parser finishes, the LHS and RHS results are
  -- combined.
  --
  -- In command line parsing, this is used by 'Options.OptStream.beforeDashes'.
  -- The LHS in this case is the main options parser for an application, and
  -- the RHS matches @"--"@. If the user passes @"--"@ on the command line, it
  -- looks like EOF to the main options parser.
  --
  -- Note: This operator is "natural". The actual inputs consumed by the LHS
  -- parser always precede the ones consumed by the RHS in the stream. In this
  -- sense '<-#>' is similar to '<*>', which has the same property. The
  -- difference between them is that in '<*>' the RHS parser is "patient": it
  -- doesn't start looking at inputs until the LHS parser has finished.
  -- Contrast this with '<-#>', where the RHS is "impatient": the RHS starts
  -- looking at inputs a.s.a.p. and has the ability to terminate the LHS.
  (<-#>) :: p (a -> b) -> p a -> p b

  -- | Right-interruptive application. Similar to '<-#>' but with the roles
  -- reversed: once the left hand side (LHS) parser consumes a token, the right
  -- hand side (RHS) is terminated as if by reaching EOF.
  --
  -- Note however that both in '<-#>' and '<#->' the LHS parser looks at each
  -- token first, and the RHS parser gets to look at it only if the LHS one has
  -- skipped it.
  --
  -- Note: this operator is "unnatural". The actual inputs consumed by the LHS
  -- parser will always come /after/ the ones consumed by the RHS in the
  -- stream.
  (<#->) :: p (a -> b) -> p a -> p b

  -- | Left-interruptive alternative. This starts off running two parsers in
  -- parallel. For each input token, the left hand side (LHS) parser looks at
  -- it first. If the LHS parser skips a token, the right hand side (RHS)
  -- parser gets a chance to look at it.
  --
  -- If the LHS parser finishes before the RHS one consumes any tokens, the LHS
  -- parser "wins": its result becomes the result of the compound parser.
  --
  -- If, on the other hand, the RHS parser consumes a token before the LHS
  -- parser has finished, the LHS parser is terminated. The state of the LHS
  -- parser is discarded, all the tokens it has consumed are lost. The RHS
  -- parser takes over and gets to finish the parse.
  --
  -- In command line parsing, this is used by 'Options.OptStream.withHelp' to
  -- implement the @--help@ flag. In this case the LHS is the main options
  -- parser for an application, and the RHS matches @"--help"@. If the user
  -- passes @"--help"@ anywhere on the command line, the normal argument
  -- parsing gets interrupted and help information is returned instead.
  (<-|>) :: p a -> p a -> p a

  -- | Right-interruptive alternative. Similar to '<-|>' but with the roles
  -- reversed: if the left hand side (LHS) parser consumes a token before the
  -- right hand side (RHS) one has finished, the RHS parser is terminated.
  --
  -- Note however that both in '<-|>' and '<|->' the LHS parser looks at each
  -- token first, and the RHS parser gets to look at it only if the LHS one has
  -- skipped it.
  (<|->) :: p a -> p a -> p a

  -- | Skips all input tokens except EOF, then returns @()@. See also:
  -- 'orElse'.
  eof :: p ()

  -- | Zero or more. This will run the given parser repeatedly until EOF is
  -- reached and gather results in a list.
  many :: p a -> p [a]
  many p a
pa = p [a]
pas where
    pas :: p [a]
pas = ((:) (a -> [a] -> [a]) -> p a -> p ([a] -> [a])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
pa p ([a] -> [a]) -> p [a] -> p [a]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> p [a]
pas) p [a] -> p [a] -> p [a]
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> [a] -> p [a]
forall (p :: * -> *) a. SelectiveParser p => a -> p a
orElse []

  -- | One or more. This will run the given parser repeatedly until EOF is
  -- reached and gather results in a list. Will refuse to consume EOF unless
  -- at least one item has been parsed.
  some :: p a -> p [a]
  some p a
pa = (:) (a -> [a] -> [a]) -> p a -> p ([a] -> [a])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
pa p ([a] -> [a]) -> p [a] -> p [a]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> p a -> p [a]
forall (p :: * -> *) a. SelectiveParser p => p a -> p [a]
many p a
pa

  -- | Zero or one. This will try running the given parser, but will return
  -- 'Nothing' if the parser never consumes any tokens.
  optional :: p a -> p (Maybe a)
  optional p a
pa = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> p a -> p (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
pa p (Maybe a) -> p (Maybe a) -> p (Maybe a)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe a -> p (Maybe a)
forall (p :: * -> *) a. SelectiveParser p => a -> p a
orElse Maybe a
forall a. Maybe a
Nothing

  -- | Bounded number of items. @'between' l u x@ will try running the parser
  -- @x@ at least @l@ times in sequence, and fail if EOF is reached before @l@
  -- items have been parsed.
  --
  -- Will finish the parse when either EOF is reached or @u@ items have been
  -- parsed.
  between :: Int
             -- ^ Lower bound (l).
          -> Int
             -- ^ Upper bound (u).
          -> p a
          -> p [a]
  between Int
low Int
high p a
pa
    | Int
0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
low = String -> p [a]
forall a. HasCallStack => String -> a
error String
"between: low is negative"
    | Int
low Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
high = String -> p [a]
forall a. HasCallStack => String -> a
error String
"between: low > high"
    | Bool
otherwise = Int -> Int -> p [a]
forall t a. (Eq t, Eq a, Num t, Num a) => t -> a -> p [a]
build Int
low Int
high where
      build :: t -> a -> p [a]
build t
0 a
0 = [a] -> p [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
      build t
0 a
n = (:) (a -> [a] -> [a]) -> p a -> p ([a] -> [a])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
pa p ([a] -> [a]) -> p [a] -> p [a]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t -> a -> p [a]
build t
0 (a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
1) p [a] -> p [a] -> p [a]
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> [a] -> p [a]
forall (p :: * -> *) a. SelectiveParser p => a -> p a
orElse []
      build t
l a
h = (:) (a -> [a] -> [a]) -> p a -> p ([a] -> [a])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
pa p ([a] -> [a]) -> p [a] -> p [a]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> t -> a -> p [a]
build (t
l t -> t -> t
forall a. Num a => a -> a -> a
- t
1) (a
h a -> a -> a
forall a. Num a => a -> a -> a
- a
1)

  -- | Permutation. Will try to parse one item by each of the given parsers, in
  -- any order.
  --
  -- Just like '<|>' this doesn't offer any back-tracking. All the parsers will
  -- get a chance to look at each input token one after another.  When one of
  -- the parsers consumes a token, that parser will run until it finishes the
  -- parse. Then the remaining parsers will continue the process. When all the
  -- parsers have produced a value the compound parser will finish and produce
  -- a list of results. The returned items will be in the same order as they
  -- appear in the stream.
  --
  -- In general, this is less convenient than simply combining all your parsers
  -- with '<#>'. However, you can use 'perm' if you care about the order in
  -- which the items appear in the stream.
  perm :: [p a] -> p [a]
  perm [] = [a] -> p [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
  perm [p a]
xs = [p a] -> [p a] -> p [a]
forall (f :: * -> *) a.
SelectiveParser f =>
[f a] -> [f a] -> f [a]
enumerate [] [p a]
xs where
    enumerate :: [f a] -> [f a] -> f [a]
enumerate [f a]
_ [] = f [a]
forall (f :: * -> *) a. Alternative f => f a
empty
    enumerate [f a]
ys' (f a
y:[f a]
ys)
      =   ((:) (a -> [a] -> [a]) -> f a -> f ([a] -> [a])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f a
y f ([a] -> [a]) -> f [a] -> f [a]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [f a] -> f [a]
forall (p :: * -> *) a. SelectiveParser p => [p a] -> p [a]
perm ([f a] -> [f a]
forall a. [a] -> [a]
reverse [f a]
ys' [f a] -> [f a] -> [f a]
forall a. [a] -> [a] -> [a]
++ [f a]
ys))
      f [a] -> f [a] -> f [a]
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> [f a] -> [f a] -> f [a]
enumerate (f a
yf a -> [f a] -> [f a]
forall a. a -> [a] -> [a]
:[f a]
ys') [f a]
ys

-- | Waits for EOF, then produces the given parse result. Intended usage is the
-- @'<|>' 'orElse'@ idiom to provide a fallback alternative for a chain of
-- parsers connected with '<|>'.
--
-- > p <|> orElse x
--
-- will run the parser @p@, and if @p@ consumes any token (normal or EOF), then
-- @p@ will finish the parse. If @p@ doesn't consume any tokens at all and
-- never finishes then the alternative parser will produce the value @x@ upon
-- receiving EOF.
--
-- Note that 'orElse' has the same type as 'pure': @a -> p a@. They produce the
-- same parse result. However, unlike 'orElse' 'pure' finishes the parse
-- immediately, without waiting for EOF. This makes 'pure' unsuitable as a
-- fallback alternative most of the time.
orElse :: SelectiveParser p => a -> p a
orElse :: a -> p a
orElse a
a = p ()
forall (p :: * -> *). SelectiveParser p => p ()
eof p () -> p a -> p a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> a -> p a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a

-- | Convenience wrapper around 'many'. Will start with a given value of type
-- @a@, and then will parse zero or more "updates" of type @a -> a@. Updates
-- will be applied to the original value left-to-right until EOF is reached, at
-- which point the final updated value will be produced.
applyMany :: SelectiveParser p => a -> p (a -> a) -> p a
applyMany :: a -> p (a -> a) -> p a
applyMany a
a p (a -> a)
pf = (a -> (a -> a) -> a) -> a -> [a -> a] -> a
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (((a -> a) -> a -> a) -> a -> (a -> a) -> a
forall a b c. (a -> b -> c) -> b -> a -> c
flip (a -> a) -> a -> a
forall a. a -> a
id) a
a ([a -> a] -> a) -> p [a -> a] -> p a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p (a -> a) -> p [a -> a]
forall (p :: * -> *) a. SelectiveParser p => p a -> p [a]
many p (a -> a)
pf

-- | Convenience wrapper around 'some'. Like 'applyMany' but will insist on
-- parsing at least one update of type @a -> a@. If no update items are parsed
-- from the input then 'applySome' will refuse to consume EOF.
applySome :: SelectiveParser p => a -> p (a -> a) -> p a
applySome :: a -> p (a -> a) -> p a
applySome a
a p (a -> a)
pf = (a -> (a -> a) -> a) -> a -> [a -> a] -> a
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (((a -> a) -> a -> a) -> a -> (a -> a) -> a
forall a b c. (a -> b -> c) -> b -> a -> c
flip (a -> a) -> a -> a
forall a. a -> a
id) a
a ([a -> a] -> a) -> p [a -> a] -> p a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p (a -> a) -> p [a -> a]
forall (p :: * -> *) a. SelectiveParser p => p a -> p [a]
some p (a -> a)
pf

-- | Like '<#>' but ignores the value produced by the right hand side parser.
(<#) :: SelectiveParser p => p a -> p b -> p a
p a
a <# :: p a -> p b -> p a
<# p b
b = a -> b -> a
forall a b. a -> b -> a
const (a -> b -> a) -> p a -> p (b -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
a p (b -> a) -> p b -> p a
forall (p :: * -> *) a b.
SelectiveParser p =>
p (a -> b) -> p a -> p b
<#> p b
b

-- | Like '<#>' but ignores the value produced by the left hand side parser.
(#>) :: SelectiveParser p => p a -> p b -> p b
p a
a #> :: p a -> p b -> p b
#> p b
b = (p a
a p a -> (b -> b) -> p (b -> b)
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> b -> b
forall a. a -> a
id) p (b -> b) -> p b -> p b
forall (p :: * -> *) a b.
SelectiveParser p =>
p (a -> b) -> p a -> p b
<#> p b
b

-- | Like '<#>' but with the types of the arguments swappped. Note that @a
-- '<##>' f@ is not the same as @f '<#>' a@. In both '<#>' and '<##>' the left
-- hand side parser looks at each input token before the right hand side
-- parser.
(<##>) :: SelectiveParser p => p a -> p (a -> b) -> p b
p a
a <##> :: p a -> p (a -> b) -> p b
<##> p (a -> b)
f = (\a
x a -> b
y -> a -> b
y a
x) (a -> (a -> b) -> b) -> p a -> p ((a -> b) -> b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
a p ((a -> b) -> b) -> p (a -> b) -> p b
forall (p :: * -> *) a b.
SelectiveParser p =>
p (a -> b) -> p a -> p b
<#> p (a -> b)
f

-- | Like '<-#>' but ignores the value produced by the right hand side parser.
(<-#) :: SelectiveParser p => p a -> p b -> p a
p a
a <-# :: p a -> p b -> p a
<-# p b
b = a -> b -> a
forall a b. a -> b -> a
const (a -> b -> a) -> p a -> p (b -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
a p (b -> a) -> p b -> p a
forall (p :: * -> *) a b.
SelectiveParser p =>
p (a -> b) -> p a -> p b
<-#> p b
b

-- | Like '<-#>' but ignores the value produced by the left hand side parser.
(-#>) :: SelectiveParser p => p a -> p b -> p b
p a
a -#> :: p a -> p b -> p b
-#> p b
b = (p a
a p a -> (b -> b) -> p (b -> b)
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> b -> b
forall a. a -> a
id) p (b -> b) -> p b -> p b
forall (p :: * -> *) a b.
SelectiveParser p =>
p (a -> b) -> p a -> p b
<-#> p b
b

-- | Like '<-#>' but with the types of the arguments swappped. Note that @a
-- '<-##>' f@ is not the same as @f '<#->' a@. In both cases the parser @a@
-- will be gracefully terminated once @f@ consumes an input. However, in @a
-- '<-##>' f@ it is @a@ that gets the first look at each input token, whereas in
-- @f '<#->' a@ it is @f@.
(<-##>) :: SelectiveParser p => p a -> p (a -> b) -> p b
p a
a <-##> :: p a -> p (a -> b) -> p b
<-##> p (a -> b)
f = (\a
x a -> b
y -> a -> b
y a
x) (a -> (a -> b) -> b) -> p a -> p ((a -> b) -> b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
a p ((a -> b) -> b) -> p (a -> b) -> p b
forall (p :: * -> *) a b.
SelectiveParser p =>
p (a -> b) -> p a -> p b
<-#> p (a -> b)
f

-- | Like '<#->' but ignores the value produced by the right hand side parser.
(<#-) :: SelectiveParser p => p a -> p b -> p a
p a
a <#- :: p a -> p b -> p a
<#- p b
b = a -> b -> a
forall a b. a -> b -> a
const (a -> b -> a) -> p a -> p (b -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
a p (b -> a) -> p b -> p a
forall (p :: * -> *) a b.
SelectiveParser p =>
p (a -> b) -> p a -> p b
<#-> p b
b

-- | Like '<#->' but ignores the value produced by the left hand side parser.
(#->) :: SelectiveParser p => p a -> p b -> p b
p a
a #-> :: p a -> p b -> p b
#-> p b
b = (p a
a p a -> (b -> b) -> p (b -> b)
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> b -> b
forall a. a -> a
id) p (b -> b) -> p b -> p b
forall (p :: * -> *) a b.
SelectiveParser p =>
p (a -> b) -> p a -> p b
<#-> p b
b

-- | Like '<#->' but with the types of the arguments swappped. Note that @a
-- '<##->' f@ is not the same as @f '<-#>' a@. In both cases the parser @f@
-- will be gracefully terminated once @a@ consumes an input. However, in @a
-- '<##->' f@ it is @a@ that gets the first look at each input token, whereas in
-- @f '<-#>' a@ it is @f@.
(<##->) :: SelectiveParser p => p a -> p (a -> b) -> p b
p a
a <##-> :: p a -> p (a -> b) -> p b
<##-> p (a -> b)
f = (\a
x a -> b
y -> a -> b
y a
x) (a -> (a -> b) -> b) -> p a -> p ((a -> b) -> b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p a
a p ((a -> b) -> b) -> p (a -> b) -> p b
forall (p :: * -> *) a b.
SelectiveParser p =>
p (a -> b) -> p a -> p b
<#-> p (a -> b)
f


-- TODO: Make wrappers to access <#> through <*> etc.