I have this parser definition:
newtype Parser a = P { getParser :: String -> Maybe (a, String) }
I also have this function:
functionMatching :: Parser (Char, String, Char)
functionMatching = (,,) <$> spot (`elem` "\\") <*> getWord <*> spot (`elem` ".")
How can I make the below function returning the middle element from (Char, String Char)
functionCons:: Parser (Char, String, Char) -> (String, String)
functionCons = undefined
Example:
getParser functionMatching "\\x.y"
Just (('\\',"x",'.'),"y")
I want to extract x and y.
Thanks!
It will be something like:
functionCons (P p) = P $ fmap (\((_,x,_), s) -> (x,s)) . p
But I suggest that you declare Parser a
a functor:
newtype Parser a = P { getParser :: String -> Maybe (a, String) }
deriving (Functor)
functionCons :: Parser (a,b,c) -> Parser b
functionCons = fmap (\(_,x,_) -> x)
This of course isn't quite Parser (a,b,c) -> (b, String)
, but you need to see if you really need to unJust
the result. For example:
functionCons :: Parser (a,b,c) -> String -> (b,String)
functionCons = unJust . fmap (\(_,x,_) -> x) where
unJust (P p) s = case p s of
Just x -> x
-- if Nothing happens, it will throw a unmatched pattern
As has been correctly noted in the comments, the type is not the same as requested. It is not possible to get the exact signature Parser (a,b,c) -> (b, String)
without functionCons
providing the String
to be parsed.
There are two issues here:
I think you are not using applicatives to the extent haskell allows. functionMatching
returns the delimiting characters, only to have them discarded later. To discard Parser matches, use *>
and <*
:
functionMatching''' :: Parser String
functionMatching''' = spot (`elem` "\\") *> getWord <* spot (`elem` ".")
functionCons''' :: String -> (String, String)
functionCons''' = fromJust . getParser functionMatching'''
How <*>
, *>
and <*
work is easily memorized, they only return what >
and <
point to:
f <*> x: fx
x *> y: y
x <* y: x
There is a way more idiomatic way to use parsers. Don't extract the unparsed String
of Maybe (a,String)
, parse it instead! That is one more call to getWord
.
functionMatching' :: Parser (String, String)
functionMatching' = (,) <$> (spot (=='\\') *> getWord <* spot (=='.')) <*> getWord
functionCons' :: String -> (String, String)
functionCons' = fromJust . evalParser functionMatching'
-- evalParser discards the unparsed String
evalParser :: Parser a -> String -> Maybe a
evalParser p s = fst <$> getParser p s
evalParser
is a useful function analogous to runState, evalState, execState you will want to export.
The idea of parsers is to not leave the parser prematurely. The code above will encounter an error ( fromJust
does this) if there is no match. haskell uses Maybe
s for that, and a Maybe
already is built into the parser. I do not know what you want to do with that (String,String)
, but you probably want to pass it to a function f :: String -> String -> b
. Then a
functionMatching'' :: Parser b
functionMatching'' = f <$> (spot (=='\\') *> getWord <* spot (=='.')) <*> getWord
will handle mismatches better.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.