[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...
More information about the Haskell-Cafe