Domain Specific Embedded Languages

A common problem in software development

Reading: DSL for the Uninitiated by Debasish Ghosh

EDSL vs. DSL

EDSL: Parts

EDSL Part Description
Types Model a concept
Constructors Construct the simplest elements of such types
Combinators Build complex elements from simpler ones
Run functions Observe the EDSL elements, possibly producing side-effects when doing so

Let us get into a specific first in order to create a EDSL in Haskell.

Shapes: a simple EDSL for vectorial graphics

code

Types and constructors

Some basic combinators

A run (observation) function

Shapes: the interface

Implementation: shallow embedding

Transformation matrices

Recommended reading

Shape rotation

Points, Vectors, and Matrices in a separate module

Alternative implementation : deep embedding

Shallow vs. Deep embedding

Rendering a shape to ASCII-art

Discussion

Signal: Another EDSL

How do we program with it?

code

More operations

Implementation: shallow embedding

We will model signals as Haskell functions of time Time -> a

type Time = Double
newtype Signal a = Sig {unSig :: Time -> a}

constS :: a -> Signal a
constS x = Sig (const x)

timeS :: Signal Time
timeS = Sig id

($$) :: Signal (a -> b) -> Signal a -> Signal b
fs $$ xs = Sig (\t -> unSig fs t  (unSig xs t))

mapT :: (Time -> Time) -> Signal a -> Signal a
mapT f xs = Sig (unSig xs . f)

sample :: Signal a -> Time -> a
sample = unSig

Implementation: deep embedding

type Time = Double
data Signal a where
  ConstS :: a -> Signal a
  TimeS  :: Signal Time
  MapT   :: (Time -> Time) -> Signal a -> Signal a
  (:$$)  :: Signal (a -> b) -> Signal a -> Signal b

constS = ConstS
timeS  = TimeS
...

The run function generates the functions of type Time -> a (most of the work is here!)

-- | Sampling a signal at a given time point.
sample (ConstS x)  = const x
sample TimeS       = id
sample (f :$$ s)   = \t -> sample f t $ sample s t
sample (MapT f s)  = sample s . f

Go live!

code

Summary