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

Wikipedia

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 { sample :: Time -> a }

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

timeS :: Signal Time
timeS = Sig id

applyS :: Signal (a -> b) -> Signal a -> Signal b
fs `applyS` xs = Sig (\ t -> sample fs t (sample xs t))

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

sample :: Signal a -> Time -> a

signal :: (Time -> a) -> Signal a
signal = Sig

Implementation: deep embedding

type Time = Double
data Signal a where
  ConstS :: a -> Signal a
  TimeS  :: Signal Time
  MapT   :: (Time -> Time) -> Signal a -> Signal a
  ApplyS :: 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 (ApplyS fs xs) = \ t -> sample fs t (sample xs t)
sample (MapT f xs)    = sample xs . f

Go live!

code

Summary