
On Thu, Oct 15, 2015 at 9:57 AM, Ian Bloom
Hi, 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.
Yeah, if the order of computations doesn't matter, then the monad is commutative. If you want to distinguish "finished computations", then you should make that distinction in the types; for example: data WHNF m a where Val :: a -> WHNF m a Lam :: (a -> Exp m b) -> WHNF m (a -> b) -- ...other value constructors of your DSL go here... data Exp m a where -- | Do some side effects and then return a value. Exp :: m (WHNF m a) -> Exp m a N.B., this version collapses chains of (the old)Exp data constructor, forcing them to all be bundled up together. That has its ups and downs. On the upside, you know you'll get a WHNF out after running stuff. On the downside, maybe sometimes you'll want to run the first part of the monad stuff just once, and then pause things so you can run more effects repeatedly (i.e., the ability to package up the type m(m(WHNF m a)) so you can run the outer m once, and then the inner m repeatedly). If you need that latter ability, then you should use this instead: data Exp m a where Now :: m (WHNF m a) -> Exp m a Later :: m (Exp m a) -> Exp m a -- Live well, ~wren