<div dir="ltr">Hello all,<br><br>I'm trying to make an IMAP DSL and I'm face to an annoying issue (all the examples after are selected pieces of this: <a href="https://github.com/blackheaven/smoothmail">https://github.com/blackheaven/smoothmail</a>).<br>Here we are, IMAP provide a way to statefully interact with a server.<br>For example:<br><br><div style="margin-left:40px">select "A" -- Select folder 'A'<br>searchAll -- Get the list of UID (message identifiers) [1, 2, 3]<br></div><br>But<br><br><div style="margin-left:40px">select "B"<br>searchAll -- Get [4, 5]<br></div><br>I decided to use the Free Monad because it seems well suite for what I'm doing and I end-up with something like that:<br><br><div style="margin-left:40px">data ImapF next =<br>         Select DirectoryName (Maybe DirectoryDescription -> next)<br>       | <span class="">Noop</span>                                      (<span class="">DirectoryDescription</span> -> next)<br>       | Search MailSearch (Maybe [UID] -> next)<br>-- Functor instance<br>type Imap = Free ImapF<br><br>searchAll :: Imap (Maybe [UID])<br>searchAll = liftF $ Search undefined id<br>select :: DirectoryName -> Imap (Maybe DirectoryDescription)<br>select directory = liftF $ Select directory id<br></div><br>My main problem is the following: if I do a select of an unknown directory, I should stop the computation. My first thought was Monad Transformers.<br>So here are the types:<br><div style="margin-left:40px">newtype FreeT f m a = FreeT { runFreeT :: m (FreeF f a (FreeT f m a)) }<br></div><br>Such that f is a functor and m a monad.<br>If I do a<br><div style="margin-left:40px">type Imap = FreeT ImapF Maybe<br></div><br>I'll end up with some Maybe (ImapF a) which not expresses that the evaluation can fails but that the expression construction can fails.<br>Then I thought harder and ends up with that:<br><br>type Imap = FreeT Maybe (Free ImapF)<br><br>Ok, that seems better, but all the available operations can't fail.<br>I also have had a look at extensible effects and I think I'm stuck with the same issue of my first attempt.<br><br>My goal is to provide flexibility for those who want to continue the evaluation, but to provide an API with less boilerplate in the default case.<br><br>If you have any ideas/hints/comments, I'll be happy to read them.<br>If you have any questions, I'll do my best to answer them and to make disappear all doubt and ambiguity.<br><br>Thanks in advance for your help.<br>Regards.<br></div>