Reputation: 23135
Using the attoparsec library, I've written this function here:
satisfyMaybe :: (Char -> Maybe a) -> Parser a
satisfyMaybe f =
(fromJust . f) <$> satisfy (isJust . f)
Which basically applies f
to the next character, and if it's Just x
, then returns x
, else fails the parse.
The thing is, I can't work out how to write this without using potentially failing functions like fromJust
. I believe my code above is correct anyway and will never fail, but I feel like I'm using the library wrong if I need an unsafe function just to conditionally apply a function to a character from the input text.
Is there a way to use the library to write this function without fromJust
or similar incomplete functions?
Upvotes: 3
Views: 52
Reputation: 3426
I haven't run this code but I would try something like this:
satisfyMaybe :: (Char -> Maybe a) -> Parser a
satisfyMaybe f =
try $ do
c <- anyChar
case (f c) of
Just x -> pure x
Nothing -> fail $ cons c " does not satisfy"
Upvotes: 0
Reputation: 476493
Essentially we can replicate what satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Parser a
[Hackage] does [src]:
satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Parser a satisfyWith f p = do h <- peekWord8' let c = f h if p c then advance 1 >> return c else fail "satisfyWith" {-# INLINE satisfyWith #-}
It thus first peeks the next word8'
in case it satisfies the condition p c
, it advances and returns c
, otherwise it fails.
We thus can use this as:
import Data.ByteString.Internal(w2c)
import Data.Attoparsec.Text as DAT
satisfyMaybe :: (Char -> Maybe a) -> Parser a
satisfyMaybe f p = do
h <- peekWord8'
case f (c2w h) of
Just r -> DAT.take 1 >> pure r
_ -> fail "satisfyMaybe"
Upvotes: 3