2

So I am writing my own parser which is almost done, however I keep on getting stuck with the return of my function. My return is a case, but within the case I have to do a parse, which I can't manage to make it work.

parseCompontntsTile :: Tile -> Parser Tile
parseCompontntsTile (Tile pos fix wiel) = 
    do  parseWhiteSpace
        patern <- match "pos:" `mplus`     match "fixed:" `mplus` match "wheel:"
        return (case patern of
                 "pos"   -> (Tile  parsePosition  fix  wiel)
                 "fixed" -> (Tile  pos     parseFixed  wiel)
                 "wheel" -> (Tile  pos     fix    parseWiel) )

The function parsePosition is from the type parsePosition :: Parser Coord; the constructor of tile is Coord Bool Bool.

This of course doesn't work because parsePosition returns Parser Coord and it expects a Coord (without the "parse"). Normally I would just 'unpack' it, however, how would I do this within a case ?

thx for the help

Will Ness
  • 70,110
  • 9
  • 98
  • 181
swaffelay
  • 323
  • 2
  • 10

2 Answers2

5

Normally I would just 'unpack' it, however, how would I do this within a case ?

You need to "push" the final return inside the case branches first

pattern <- match "pos:" `mplus`  ....
case pattern of
   "pos"   -> return (Tile  parsePosition  fix  wiel)
   "fixed" -> return (Tile  pos     parseFixed  wiel)
   "wheel" -> return (Tile  pos     fix    parseWiel)

Now, having the branches being run in the parser monad, you can unpack as usual:

pattern <- match "pos:" `mplus`  ....
case pattern of
   "pos"   -> do  -- alternative 1
      pp <- parsePosition
      return (Tile pp fix wiel)
   "fixed" -> -- alternative 2
      (\pf -> Tile pos pf wiel) <$> parseFixed
   "wheel" -> ...
chi
  • 111,837
  • 3
  • 133
  • 218
1

Something like

parseCompontntsTile :: Tile -> Parser Tile
parseCompontntsTile (Tile pos fix wiel) = 
    do  parseWhiteSpace
        pattern <- match "pos:" `mplus` match "fixed:" `mplus` match "wheel:"
        case pattern of
                 "pos"   -> do { pos <- parsePosition ; return $ Tile pos fix wiel }
                 "fixed" -> do { fix <- parseFixed    ; return $ Tile pos fix wiel }
                 "wheel" -> do { wiel <- parseWiel    ; return $ Tile pos fix wiel } 

assuming that those parseXXXX items are parsers.

Or restructure it for less code duplication, by the use of shadowing to "update" the corresponding variable, as

parseCompontntsTile :: Tile -> Parser Tile
parseCompontntsTile (Tile pos fix wiel) = 
    do  parseWhiteSpace
        pattern <- match "pos:" `mplus` match "fixed:" `mplus` match "wheel:"
        (pos,fix,wiel) <- case pattern of
                 "pos"   -> do { pos <- parsePosition ; return (pos,fix,wiel) }
                 "fixed" -> do { fix <- parseFixed    ; return (pos,fix,wiel) }
                 "wheel" -> do { wiel <- parseWiel    ; return (pos,fix,wiel) } 
        -- .....
        return $ Tile pos fix wiel

in case the actual post-processing step is more involved (i.e. there's more steps after the case, before the final return).

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • How is the second one less code duplication? Sure, we are saying `Tile` fewer times, but now we're saying `(,,)` more times. – Daniel Wagner Jul 31 '19 at 13:40
  • @DanielWagner *"in case"* etc as in the answer -- i.e. there could be some more steps before the final return, which I hinted at with the `-- .....`. what I wanted was the ability to continue *after* the case. the first (most immediate) translation is a split (into the three tails), the second connects back the split ends into one line so to speak (in the control flow diagram). – Will Ness Jul 31 '19 at 14:41