<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>Type families can be used to great effect in this area. For instance, in Potential (<a href="http://potential-lang.org">http://potential-lang.org</a>) we use two tricks for making sure that the combinators in our EDSL are are obeying our rules for composition:</div><div><br></div><div>(a) We use type families as type-level functions for describing how state transforms, and</div><div>(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).</div><div><br></div><div>We use this combo in many different ways. For instance, in our EDSL we have certain combinators which <i>cannot</i> be followed by any other combinators (we say they are "terminal"). We have others which <i>can</i> 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).</div><div><br></div><div>We then have a type family</div><div><br></div><div>class ComposeC a b where type ComposeT a b</div><div><br></div><div>and instances like</div><div><br></div><div><div>instance CombposeC Terminal Unmodeled where</div><div> type ComposeT Terminal Unmodeled = Terminal</div></div><div><br></div><div>instance CombposeC Composable Terminal where</div><div> type ComposeT Composable Terminal = Terminal</div><div><br></div><div><div>instance CombposeC Composable Unmodeled where</div><div> type ComposeT Composable Unmodeled = Composable</div></div><div><br></div><div><div><div>instance CombposeC Unmodeled Composable where</div><div> type ComposeT Unmodeled Composable = Composable</div></div></div><div><br></div><div><div>instance CombposeC Composable Composable where</div><div> type ComposeT Composable Composable = Composable</div></div><div><br></div><div><div>instance CombposeC Unmodeled Unmodeled where</div><div> type ComposeT Unmodeled Unmodeled = Unmodeled</div></div><div><br></div><div>Our >>= operator now looks like</div><div><br></div><div>(>>=) :: (ComposeC ct ct') => m ct a -> (a -> m ct' b) -> m (Compose ct ct') b</div></div><div><br></div><div><br></div><div>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...").</div><div><br></div><br><div><div>On Sep 17, 2010, at 11:27 AM, Günther Schmidt wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div>Hello,<br><br>I'd want to create a EDSL where I want to be able to statically ensure <br>that expressions can only be built according to a particular "state".<br><br>Like in a network application, SMTP client for example, where I can only <br>issue commands if the application is in a certain state.<br><br>Are there any Haskell examples for this sort of thing?<br><br>Günther<br><br>_______________________________________________<br>Haskell-Cafe mailing list<br><a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>http://www.haskell.org/mailman/listinfo/haskell-cafe<br></div></blockquote></div><br></body></html>