<div dir="ltr">On Thu, Apr 6, 2017 at 1:53 PM, Bertram Felgenhauer via Haskell-Cafe <span dir="ltr"><<a href="mailto:haskell-cafe@haskell.org" target="_blank">haskell-cafe@haskell.org</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class="gmail-">Ertugrul Söylemez wrote:<br>
> > Could someone outline for me the downsides of using the Prompt monad?<br>
><br>
> For one thing I find its definition to be overcomplicated for what it<br>
> does.<br>
<br>
</span>I'm assuming that this is referring to the MonadPrompt package...<br>
If you mean the type, it's essentially the same as<br>
<br>
    <a href="http://hackage.haskell.org/package/free-4.12.4/docs/src/Control-Monad-Free-Church.html#F" rel="noreferrer" target="_blank">http://hackage.haskell.org/<wbr>package/free-4.12.4/docs/src/<wbr>Control-Monad-Free-Church.<wbr>html#F</a><br>
<br>
after plugging in PromptF' p (see below). The point is to make left<br>
associative use of >=> efficient.<br>
<span class="gmail-"><br>
> For another the same can be achieved with free monads in a more<br>
> transparent and flexible manner:<br>
><br>
>     import Control.Monad.Free.Class<br>
><br>
>     data PromptF a b x = PromptF (b -> x) a<br>
>         deriving (Functor)<br>
<br>
</span>More accurately,<br>
<br>
    data PromptF' p x = forall a. PromptF (a -> x) (p a)<br>
<br>
(with the obvious Functor instance).<br>
<br>
The existential highlights an important design idea of the Prompt monad,<br>
namely that a monadic DSL would be specified by a GADT (p a), where `a`<br>
represents the result type of the corresponding operation. So, for a<br>
state monad, one would use<br>
<br>
    data PromptState s a where<br>
        Get :: PromptState s s<br>
        Put :: s -> PromptState s ()<br>
<br>
which defines a "get" operation without arguments that returns a value<br>
of type s, and a "put" operation that takes a value of type s, but<br>
returns nothing.<br>
<br>
This is slightly less expressive than free monads (the main loss, I<br>
believe, is that a prompt GADT cannot express that an operation is<br>
necessarily a leaf of computations; while free monads can also express<br>
non-determinism, that does not give rise to any useful guarantees for<br>
the resulting behavior, as far as I can see). I would argue that prompt<br>
GADTs are sufficient for many applications, and that thinking in terms<br>
of interfaces is more natural to many programmers than thinking in terms<br>
of unfolding computations.<br>
<br></blockquote><div><br></div><div>It’s worth noting that Prompt p is the free monad for a type constructor p, just as Free f is the free monad for a Functor f. As such, when p is a Functor, they are isomorphic.</div><div><br></div><div><div>data Free f a = Var a | Wrap (f (Free f a))</div><div><br></div><div>newtype Prompt p a = Prompt { unPrompt :: forall b. (forall i. p i -> (i -> b) -> b) -> (a -> b) -> b }</div><div>-- equivalently, Prompt p a = Done a | forall i. Prompt (p i) (i -> Prompt p a)</div><div><br></div><div>prompt :: p a -> Prompt p a</div><div>prompt p = Prompt $ \c -> c p</div><div><br></div><div>promptFree :: Free f a -> Prompt f a</div><div>promptFree (Var a) = return a</div><div>promptFree (Wrap f) = prompt f >>= promptFree</div><div><br></div><div>freePrompt :: Functor f => Prompt f a -> Free f a</div><div>freePrompt m = unPrompt m (\f k -> Wrap (fmap k f)) Var</div></div><div><br></div><div>Thus, it’s entirely possible to do non-determinism and halting with Prompt.</div><div><br></div><div>Just to have a concrete example, here’s an interface that prints strings and has non-determinism.</div><div><br></div><div>data W a where</div><div>    Print :: String -> W ()</div><div>    End :: W a</div><div>    Choose :: a -> a -> W a</div><div><br></div><div>Note that End and Choose are fully polymorphic. This means that an interpreter has to pass one of the two provided values to the continuation when it receives Choose, and it can’t call the continuation when it receives End.</div><div><br></div></div>-- <br><div class="gmail_signature">Dave Menendez <<a href="mailto:dave@zednenem.com" target="_blank">dave@zednenem.com</a>><br><<a href="http://www.eyrie.org/~zednenem/" target="_blank">http://www.eyrie.org/~zednenem/</a>></div>
</div></div>