@hackage grab0.0.0.9
Applicative non-linear consumption
Installation
Dependencies (1)
Dependents (1)
@hackage/grab-form
The Grab type
A grab consumes some portion (none, part, or all) of
its input bag
, and returns a residue
consisting of
the unconsumed input, some monoidal log
(e.g. a list
of error messages), and some desideratum
(the object
of desire) produced from the consumed input, or
Nothing
if the grab failed.
newtype Grab bag residue log desideratum = Grab ( bag -> (residue, log, Maybe desideratum) )
Grabs are useful as parsers for inputs such as JSON objects or lists of form parameters, where the input data is not necessarily given linearly in the same order in which we want to consume it.
Applicative composition
A Simple
grab (where the bag
and residue
are the
same type) has an Applicative
instance.
instance (bag ~ residue, Monoid log) => Applicative (Grab bag residue log)
For example, we can create two simple list grabs, one that grabs multiples of two, and the other that grabs multiples of three:
twos, threes :: Monoid log => Control.Grab.Simple [Integer] log [Integer] twos = partition (Data.List.partition (\x -> mod x 2 == 0)) threes = partition (Data.List.partition (\x -> mod x 3 == 0))
λ> runGrabMaybe ((,) <$> twos @() <*> threes @()) [1..10] Just ([2,4,6,8,10],[3,9])
Notice that the second part of the resulting tuple contains only
the odd multiples of three. Because twos
runs first, it
consumes 6
before the threes
can get it.
Pipeline composition
a / b
is a pipeline of two grabs, where the desideratum from
a
is the bag
for b
.
.
> (/) :: Semigroup log
> => Grab bag residue log x
> -> Grab x _residue log desideratum
> -> Grab bag residue log desideratum
λ> runGrabMaybe (twos @() / threes @()) [1..10] Just [6]
λ> runGrabMaybe ((,) <$> (twos @() / threes @()) <*> threes @()) [1..10] Just ([6],[3,9])