[Haskell-cafe] Trying to write an Embedded DSL that threads a monad?

wren romano wren at community.haskell.org
Thu Oct 15 19:48:26 UTC 2015


On Thu, Oct 15, 2015 at 9:57 AM, Ian Bloom <ianmbloom at gmail.com> wrote:
> 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


More information about the Haskell-Cafe mailing list