<div dir="ltr"><span style="font-size:12.8px">Hi,</span><div style="font-size:12.8px">Thanks for your reply. I think the Monad that I chose for my example code was not the best. I've been hoping to generalize across all possible monads but the real use case arises because I have an expensive computation that I know will repeat multiple times within the evaluation of a given large expression so in my monad I want to implement a cache. If I query the cache and it has not done the computation it will perform the computation once and then return the result plus a new cache holding the result, if the computation has already been performed it is present in the cache and taken from there. In my definition of Exp there would then be one more value, say Ext that when applied to a parameter can access and modify the cache. In this case the order of evaluation doesn't affect the result of the Monad, I'm not sure if "commutative" is the right way to describe this. </div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">There is a lot to think about here but let me try playing around with your code.</div><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">Thanks,</div><div style="font-size:12.8px">Ian</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Oct 15, 2015 at 7:43 AM, wren romano <span dir="ltr"><<a href="mailto:winterkoninkje@gmail.com" target="_blank">winterkoninkje@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Wed, Oct 14, 2015 at 9:31 AM, Ian Bloom <<a href="mailto:ianmbloom@gmail.com">ianmbloom@gmail.com</a>> wrote:<br>
> Here is what I'd like from the language:<br>
><br>
> * To use haskell syntax for substitution and pattern matching rather than<br>
> implementing this myself.<br>
> * To be able to express lambdas in my language.<br>
> * To be able to embed any haskell terms including functions into the<br>
> language.<br>
> * I'd like the Haskell type checker to tell me about bad terms.<br>
> * I'd like to thread a monad through the entire expression.<br>
<br>
</span>It's still not clear exactly what you want/need with that last bullet<br>
point. So I can try to offer help, but have no idea if this is on the<br>
right track...<br>
<span class=""><br>
<br>
> So here is the first implementation that I tried of this (full source here:<br>
> <a href="http://lpaste.net/142959" rel="noreferrer" target="_blank">http://lpaste.net/142959</a>)<br>
><br>
> data Exp m x where<br>
> Val :: m x -> Exp m x<br>
> Lam1 :: m (a -> Exp m b) -> Exp m (a -> b)<br>
> Lam2 :: m (a -> Exp m (b -> c)) -> Exp m (a -> b -> c)<br>
><br>
> a function liftE allows me to lift a haskell term into an expression:<br>
><br>
> liftE x = Val $ return x<br>
><br>
> Application is a function <@> so:<br>
><br>
> (<@>) :: forall m a b. Monad m => Exp m (a -> b) -> Exp m a -> Exp m b<br>
> (<@>) (Val f) (Val x) = Val $ f `ap` x<br>
> (<@>) (Lam2 f) (Val x) = Lam1 $ f >>= \f' -> x >>= \x' -> unLam1 $ f' x'<br>
> (<@>) (Lam1 f) (Val x) = Val $ f >>= \f' -> x >>= \x' -> unVal $ f' x'<br>
><br>
</span>>[...]<br>
<span class="">><br>
> Ok so that's a lot. I was surprised I got this working. You can see from the<br>
> code that my main gripe with this is I haven't found a way to remove the<br>
> need to specify the number of embedded lambdas using Lam1 and Lam2 (we could<br>
> easily add more) and I haven't found a way to apply a Lam to another Lam.<br>
> I'm also curious if I am reinventing the wheel, I hadn't found a library yet<br>
> that let's me do something similar.<br>
<br>
</span>So, two things to notice.<br>
<br>
First, the type for Lam2 is just a refinement of the type for Lam1.<br>
Thus, Lam2 gives you nothing new in terms of what can be made to<br>
typecheck; the only thing it gives you is the ability to make runtime<br>
decisions based on whether a particular expression was built with Lam1<br>
or Lam2 (or Val).<br>
<br>
Second, the apparent need for multiple lambdas stems from the fact<br>
that your (<@>) function needs to "count down by one" each time an<br>
argument is applied. This hides a big problem in the definition,<br>
namely that you're assuming that after the right number of arguments<br>
the resulting Exp will be built with Val; which isn't actually<br>
guaranteed by the types.<br>
<br>
After playing around with it for a while, it seems like the crux of<br>
the issue comes from not being able to embed m(Exp m a) into Exp m a.<br>
So, we can fix that by adding a new constructor:<br>
<span class=""><br>
data Exp m x where<br>
</span> Val :: m a -> Exp m a<br>
Exp :: m (Exp m a) -> Exp m a<br>
Lam :: m (a -> Exp m b) -> Exp m (a -> b)<br>
<br>
Exp f <@> x = Exp ((<@> x) <$> f)<br>
f <@> Exp x = Exp ((f <@>) <$> x)<br>
Val f <@> Val x = Val (f <*> x)<br>
Lam f <@> Val x = Exp (($) <$> f <*> x)<br>
-- TODO: Val/Lam and Lam/Lam cases...<br>
<br>
unVal :: Monad m => Exp m a -> m a<br>
unVal (Val v) = v<br>
unVal (Exp e) = e >>= unVal<br>
<br>
This at least works for the given test case with mapE, testExpression,<br>
and test— though it doesn't give exactly the same result about the<br>
number of binds. But again I'm not sure what you're really after here.<br>
<br>
(Note that, once we add the Exp constructor, we can redo Val to take a<br>
pure argument without losing anything re typeability. Though again,<br>
the exact semantics of dubious things like (>>=)-counting won't<br>
necessarily be preserved. Still, as a general rule, it makes sense for<br>
EDSLs to distinguish between pure values vs impure expressions...)<br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
Live well,<br>
~wren<br>
</font></span></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">718.755.5483<br><a href="http://ianbloom.com/" target="_blank">http://ianbloom.com/</a></div>
</div>