I am thinking about a use case of the free monad which would be a simple lexing DSL. So far I came up with some primitive operations:
data LexF r where
POP :: (Char -> r) -> LexF r
PEEK :: (Char -> r) -> LexF r
FAIL :: LexF r
...
instance Functor LexF where
...
type Lex = Free LexF
The problem I encounter is that I would like to have a CHOICE primitive that would describe an operation of trying to execute one parser and in case of failure fallback to another. Something like CHOICE :: LexF r -> LexF r -> (r -> r) -> LexF r...
...and here the stairs begin. Since r is preset at contravariant position, it is impossible (is it?) to create a valid Functor instance for Op. I came up with some other idea, which was to generalize over the type of alternative lexers, so CHOICE :: LexF a -> LexF a -> (a -> r) -> LexF r – now it works as a Functor, though the problem is with thawing it into Free, as I would normally do it with liftF:
choice :: OpF a -> OpF a -> OpF a
choice c1 c2 = liftF $ CHOICE _ _ id -- how to fill the holes :: Op a ?
I am really running out of any ideas. This of course generalizes to nearly all other combinators, I just find CHOICE a good minimal case. How to tackle it? I am okay to hear that this example is totally broken and it just won't work with Free as I would like to. But therefore, does it even make sense to write lexers/parsers in this manner?
As a general rule when working with free monads, you don't want to introduce primitives for "monadic control". For example, a
SEQUENCEprimitive would be ill-advised, because the free monad itself provides sequencing. Likewise, aCHOICEprimitive is ill-advised because this should be provided by a freeMonadPlus.Now, there is no free
MonadPlusin modern versions offreebecause equivalent functionality is provided by a free monad transformer over a list base monad, namelyFreeT f []. So, what you probably want is to define:but no
FAILorCHOICEprimitives.If you were to define
failandchoicecombinators, they would be defined by means of the list base monad using transformer magic:though there's no actual reason to define these.
SPOILERS follow... Anyway, you can now write things like:
With an interpreter for your monad primitives, in this case intrepreting them to the
StateT String []AKAString -> [(a,String)]monad:you can then:
The full example: