[Haskell-cafe] Stateful DSLs

TIMOTHY MICHAEL CARSTENS t.carstens at utah.edu
Fri Sep 17 16:35:58 EDT 2010

Type families can be used to great effect in this area.  For instance, in Potential (http://potential-lang.org) we use two tricks for making sure that the combinators in our EDSL are are obeying our rules for composition:

(a) We use type families as type-level functions for describing how state transforms, and
(b) We use a custom Monad class whose >> and >>= use our type families.  (This is only so that we can use 'do' notation; we could let go of 'do' notation and leave the Monad class alone).

We use this combo in many different ways.  For instance, in our EDSL we have certain combinators which cannot be followed by any other combinators (we say they are "terminal"). We have others which can be followed by others (we say they are "composable").  We also have a weird class of operations which don't really interact with our state and are thus able to break the rules (we say they are "unmodeled"; we only use this designation for data plumbing, like `return,' which is why it's allowed to break the rules).

We then have a type family

class ComposeC a b where type ComposeT a b

and instances like

instance CombposeC Terminal Unmodeled where
  type ComposeT Terminal Unmodeled = Terminal

instance CombposeC Composable Terminal where
  type ComposeT Composable Terminal = Terminal

instance CombposeC Composable Unmodeled where
  type ComposeT Composable Unmodeled = Composable

instance CombposeC Unmodeled Composable where
  type ComposeT Unmodeled Composable = Composable

instance CombposeC Composable Composable where
  type ComposeT Composable Composable = Composable

instance CombposeC Unmodeled Unmodeled where
  type ComposeT Unmodeled Unmodeled = Unmodeled

Our >>= operator now looks like

(>>=) :: (ComposeC ct ct') => m ct a -> (a -> m ct' b) -> m (Compose ct ct') b

There is a practical side-effect, unfortunately, which is that type-level computation in Haskell can be cumbersome (type families are lazily evaluated in GHC) and lead to hard-to-read errors (errors often manifest as "No instance for...").

On Sep 17, 2010, at 11:27 AM, Günther Schmidt wrote:


I'd want to create a EDSL where I want to be able to statically ensure
that expressions can only be built according to a particular "state".

Like in a network application, SMTP client for example, where I can only
issue commands if the application is in a certain state.

Are there any Haskell examples for this sort of thing?


Haskell-Cafe mailing list
Haskell-Cafe at haskell.org<mailto:Haskell-Cafe at haskell.org>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20100917/e9b854f7/attachment.html

More information about the Haskell-Cafe mailing list