<div dir="ltr"><div><div><div>Hi guys,<br></div>I'm still exploring some design space for DSLs, following our interesting discussion.<br><br></div>I'm trying to write the evaluator for the DSL (see below). <br></div>
For the general case, the evaluator looks like:<br><br><span style="font-family:courier new,monospace">eval :: Nomex r a -> State Game a </span><br><div><div><br></div><div>This eval function takes an expression (called Nomex), that can possibly have effects.<br>
</div><div>It returns a state monad, to allow you to modify the game state.<br><br></div><div>But for effectless instructions, it would be better to run the evaluator in the reader monad:<br><br><span style="font-family:courier new,monospace">evalNoEffect :: Nomex NoEffect a -> Reader Game a </span><br>
</div><div><br></div><div>So you can have additional guaranties that evaluating your expression will not have effects.<br></div><div><span style="font-family:courier new,monospace"><span style="font-family:arial,helvetica,sans-serif">I tried (see below), but it doesn't work for the moment: </span><br>
<br></span></div><div><span style="font-family:courier new,monospace"><br>> {-# LANGUAGE GADTs #-}<br>> {-# LANGUAGE KindSignatures, DataKinds, ScopedTypeVariables, <br>>   MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}<br>
<br>> module DSLEffects where<br><br>> import Control.Monad.Error<br>> import Control.Monad.State<br>> import Control.Monad.Reader<br>> import Data.Typeable<br><br>This is the DSL:<br>    <br>> data Effects = Effect | NoEffect<br>
<br>> data Nomex :: Effects -> * -> * where<br>>   ReadAccount  :: Nomex r Int                --ReadAccount has no effect: it can be run in whatever monad<br>>   WriteAccount :: Int -> Nomex Effect ()  --WriteAccount has effect<br>
>   SetVictory   :: Nomex NoEffect Bool -> Nomex Effect () --SetVictory don't accept effectful computations<br>>   Bind         :: Nomex m a -> (a -> Nomex m b) -> Nomex m b<br>>   Return       :: a -> Nomex r a  --wrapping a constant has no effect<br>
<br>> instance Monad (Nomex a) where<br>>   return = Return<br>>   (>>=) = Bind<br><br><br>> noEff :: Nomex NoEffect ()<br>> noEff = return ()<br><br>> hasEffect :: Nomex Effect ()<br>> hasEffect = do<br>
>    a <- ReadAccount<br>>    WriteAccount a<br><br>> data Game = Game { victory :: Nomex NoEffect Bool,<br>>                    account :: Int}<br><br><br>> eval :: Nomex r a -> State Game a <br>> eval a@ReadAccount    = liftEval $ evalNoEffect a<br>
> eval (WriteAccount a) = modify (\g -> g{account = a})<br>> eval (SetVictory v)   = modify (\g -> g{victory = v})<br>> eval a@(Return _)     = liftEval $ evalNoEffect a<br>> eval (Bind exp f)     = eval exp >>= eval . f<br>
<br>> evalNoEffect :: Nomex NoEffect a -> Reader Game a<br>> evalNoEffect ReadAccount  = asks account<br>> evalNoEffect (Return a)   = return a<br>> evalNoEffect (Bind exp f) = evalNoEffect exp >>= evalNoEffect . f<br>
<br>> liftEval :: Reader Game a -> State Game a<br>> liftEval r = get >>= return . runReader r <br></span><br><br></div><div>This is not compiling: <br><br></div><div>exceptEffect.lhs:60:15:<br>    Couldn't match type 'NoEffect with 'Effect<br>
    Inaccessible code in<br>      a pattern with constructor<br>        WriteAccount :: Int -> Nomex 'Effect (),<br>      in an equation for `evalEffect'<br>    In the pattern: WriteAccount a<br>    In an equation for `evalEffect':<br>
        evalEffect (WriteAccount a) = modify (\ g -> g {account = a})<br><br></div><div>It seems that the type of effectless computations (NoEffect) leaks in the type of effectful ones (due to the pattern matching)...<br>
</div><div><br></div><div>Thanks,<br></div><div>Corentin<br><br></div></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Feb 3, 2014 at 12:44 PM, Corentin Dupont <span dir="ltr"><<a href="mailto:corentin.dupont@gmail.com" target="_blank">corentin.dupont@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div><div><div>I saw that to write liftQD you decontruct (unwrap) the type and reconstruct it. <br>
</div>I don't know if I can do that for my Exp (which is a full DSL)...<br><br></div>Anyway, there should be a way to encode the Effect/NoEffect semantic at type level...<br>
</div>Using Oleg's parametrized monad idea (<a href="http://hackage.haskell.org/package/monad-param-0.0.2/docs/Control-Monad-Parameterized.html" target="_blank">http://hackage.haskell.org/package/monad-param-0.0.2/docs/Control-Monad-Parameterized.html</a>), I tried:<br>

<br><span style="font-family:courier new,monospace">> {-# LANGUAGE KindSignatures, DataKinds, ScopedTypeVariables, GADTs<br>>   MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}<br>

<br>> module DSLEffects where<br>> import Prelude hiding (return, (>>), (>>=))<br>> import Control.Monad.Parameterized</span><br><br>This data type will be promoted to kind level (thanks to DataKinds):<div class="">
<br>
<span style="font-family:courier new,monospace"><br>> data Eff = Effect | NoEffect</span><br><br></div>This class allows to specify the semantic on Effects (Effect + NoEffect = Effect):<br><span style="font-family:courier new,monospace"><br>

> class Effects (m :: Eff) (n::Eff) (r::Eff) | m n -> r<br>> instance Effects Effect n Effect<br>> instance Effects NoEffect n n</span><br><br>This is the DSL:<br><span style="font-family:courier new,monospace"><div class="">
<br>
> data Exp :: Eff -> * -> * where<br></div>>   ReadAccount  :: Exp NoEffect Int      --ReadAccount has no effect<br>>   WriteAccount :: Int -> Exp Effect ()  --WriteAccount has effect<br>>   Const        :: a -> Exp r a<br>

>   Bind         :: Effects m n r => Exp m a -> (a -> Exp n b) -> Exp r b --Bind comes with a semantic on effects<br>>   Fmap         :: (a -> b) -> Exp m a -> Exp m b<br><br>> instance Functor (Exp r) where<br>

>   fmap = Fmap<br><br>> instance Return (Exp r) where<br>>    returnM = Const<br><br>> instance (Effects m n r) => Bind (Exp m) (Exp n) (Exp r) where<br>>    (>>=) = Bind<br><br>> noEff :: Exp NoEffect ()<br>

> noEff = returnM ()<br><br>> hasEffect :: Exp Effect ()<br>> hasEffect = ReadAccount >> (returnM () :: Exp Effect ())</span><br><br></div>This is working more or less, however I am obliged to put the type signature on the returnM (last line): why?<br>

</div><span style="font-family:arial,helvetica,sans-serif">Furthermore, I cannot write</span><span style="font-family:courier new,monospace"><span style="font-family:arial,helvetica,sans-serif"> directly:</span><br></span><br>

<span style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">> hasEffect :: Exp Effect ()<br></span>> hasEffect = ReadAccount</span><div><div><div><br><br></div><div>Do you have a better idea?<br>

<br></div></div></div></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Feb 2, 2014 at 8:55 PM, Lindsey Kuper <span dir="ltr"><<a href="mailto:lindsey@composition.al" target="_blank">lindsey@composition.al</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>On Sun, Feb 2, 2014 at 2:42 PM, Corentin Dupont<br>
<<a href="mailto:corentin.dupont@gmail.com" target="_blank">corentin.dupont@gmail.com</a>> wrote:<br>
> you should be able to run an effectless monad in an effectful one.<br>
> How to encode this semantic?<br>
<br>
</div>In LVish we just have a `liftQD` operation that will let you lift a<br>
deterministic computation to a quasi-deterministic one (recall that<br>
deterministic computations can perform fewer effects):<br>
<br>
  liftQD :: Par Det s a -> Par QuasiDet s a<br>
<br>
So, analogously, you could have a `liftEff` and then write `liftEff<br>
noEff`.  This is also a little bit ugly, but you may find you don't<br>
have to do it very often (we rarely use `liftQD`).<br>
<span><font color="#888888"><br>
Lindsey<br>
</font></span></blockquote></div><br></div>
</div></div></blockquote></div><br></div>