[Haskell-cafe] Bool as type class to serve EDSLs.

Sebastiaan Visser sfvisser at cs.uu.nl
Wed May 27 08:32:23 EDT 2009


While playing with embedded domain specific languages in Haskell I  
discovered the Num type class is a really neat tool. Take this simple  
example embedded language that can embed primitives from the output  
language and can do function application.

 >data Expr :: * -> * where
 >  Prim :: String -> Expr a
 >  App  :: Expr (a -> b) -> Expr a -> Expr b

Take these two dummy types to represent things in the output language.

 >data MyNum
 >data MyBool

Now it is very easy to create an Num instance for this language:

 >primPlus :: Expr (MyNum -> MyNum -> MyNum)
 >primPlus = Prim "prim+"

 >instance Num (Epxr MyNum) where
 >  a + b = primPlus `App` a `App` b
 >  fromInteger = Prim . show
 >  ...

Which allows you to create very beautiful expression for your language  
embedded inside Haskell. The Haskell expression `10 * 5 + 2' produces  
a nice and well typed expression in your embedded domain.

But unfortunately, not everyone in the Prelude is as tolerant as the  
Num instance. Take the Eq and the Ord type classes for example, they  
require you to deliver real Haskell `Bool's. This makes it impossible  
make your DSL an instance of these two, because there are no `Bool's  
only `Expr Bool's.

Which brings me to the point that, for the sake of embedding other  
languages, Haskell's Prelude (or an alternative) can greatly benefit  
from (at least) a Boolean type class like this:

class Boolean a where
   ifthenelse :: a -> b -> b -> b         -- Not sure about this  

And one instance:

 >instance Boolean (Expr MyBool) where
 >  ifthenelse c a b = Prim "if-then-else" `App` c `App` a `App` b

Now we can change (for example) the Eq type class to this:

 >class Eq a where
 >  (==) :: Boolean b => a -> a -> b
 >  (/=) :: Boolean b => a -> a -> b

For which we can give an implementation for our domain:

 >primEq :: Epxr (a -> a -> MyBool)
 >primEq = Prim "=="

 >instance Eq (Expr a) where
 >  a == b = primEq `App` a `App` b

And now we get all functionality from the Prelude that is based on Eq  
(like not, &&, ||, etc) for free in our domain specific language! Off  
course there are many, many more examples of things from the standard  
libraries that can be generalised in order to serve reuse in EDSLs.

Anyone already working on such a generalized Prelude? I can imagine  
much more domains can benefit from this than my example above. Any  
interesting thoughts or pointers related to this subject?


Sebastiaan Visser

More information about the Haskell-Cafe mailing list