Skip to content

Q: thoughts on takeSome and takeMany  #57

Closed
@safareli

Description

@safareli

Recently I used List.Lazy and my expectation was that parser take 2 (many (char '0')) Will try to match character 0 maximum 2 times. But it's actually trying to match 0 until it fails. So if input to parser is 0000000 it will consume all of 0-s and result will be list of two 0-s.

To solve this issue I have implemented takeSome and takeMany for normal List:

-- | Attempt a computation `n` times, requiring at least one success.
-- |
-- | The `Lazy` constraint is used to generate the result lazily, to ensure
-- | termination.
takeSome :: forall f a. Alternative f => Lazy (f (List  a)) => Int -> f a -> f (List  a)
takeSome 0 _ = pure Nil
takeSome n v = Cons <$> v <*> defer (\_ -> takeMany (n - 1) v)

-- | Attempt a computation `n` times, returning as many successful results
-- | as possible (possibly zero).
-- |
-- | The `Lazy` constraint is used to generate the result lazily, to ensure
-- | termination.
takeMany :: forall f a. Alternative f => Lazy (f (List a)) => Int -> f a -> f (List a)
takeMany 0 _ = pure Nil
takeMany n v = takeSome n v <|> pure Nil

If Infinity was member of Int then:

some = takeSome Infinity
many = takeMany Infinity

This issue is not strictly related to Parser but i think it could be useful for parsers.
What you think if we define this functions for List/Array/....

We can have on internal definition take{Some,Many} which are taking Number (to allow use of Infinity) and define some, many, takeSome and takeMany in terms of them.

takeSome = toNumber >>> takeSome_ 
some = takeSome_ Infinity
takeMeny = toNumber >>> takeMeny_ 
meny = takeMeny_ Infinity

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions