okay so I think if you have a good, well-behaved parsing framework, you don't need a select primitive, just a compact :: f (Maybe a) -> f a primitive (in addition to Applicative and Plus), so then

select l r =
  compact (blush <$> l) <|> ((#) <$> compact (hush <$> l) <*> r)

hush :: Either a b -> Maybe b
blush :: Either a b -> Maybe a

and the syntax in my last post can look like this: no explicit match statement, just pattern matching on a pure value:

length_prefixed_aux(parser){ amt }
  // guard on amt = 0, then return an empty list
  | 0 = { amt }
    { [] }
  // otherwise we parse one, and recurse
  // (decrementing amt)
  | (n+1) = { amt }; head = parser; more = length_prefixed_aux(parser){ n }
    { head :: more }

in fact you might argue that this formulation of select is equivalent to something with compact on the outside, but again, that requires you to have a good parsing framework

what does that mean?

well the parsing framework should be able to handle backtracking and ambiguity that gets resolved on the fly

and it also is able to cope with losing the notion of what paths are exclusive

maybe in non-backtracking parsers, you can add try on the left alternative ... but you'll still do the work twice, naïvely

(i.e. if you're interpreting in a monad and not doing static analysis)

and because of how you have to re-associate applicatives to make select work, that's often a significant, multi-step parser

but if you use the static analysis to read ahead or something (Brzozowski derivative, LR parsing, stuff like that), then you can maybe share the work between the branches anyways


You must log in to comment.