## 07 May, 2010

There's a mindset that says to solve your problem, first write a language to solve your problem in, and then solve your problem in that language. And there's a mindset that says that your language should be an embedded language inside Haskell. In many ways that is appealing.

I wanted to write something that would delete old rsync snapshots. I took the domain-specific language approach, where the language specifies the retention policy for snapshots, like this:
policy = recent <||> weekly <||> monthly

meanings the final policy is to keep 'recent', 'weekly' and 'monthly' backups, with other statements defining what those three other policies mean. I won't write more about the language here - there's more on the webpage for the tool, snaprotate.

One particular piece of this I don't feel terribly comfortable with, and thats how to invoke/run the policy files.

I can imagine two different interfaces:
$snaprotate -f policyfile  or $ policyfile


I took the second approach, making policies first order unix executables - commands that can be run like any other command.

In unix tradition the way you indicate the language of a script is with a shebang line (#!/something) at the start of the script.

So then I want my scripts to look like something like this:
#!/usr/bin/snaprotate

policy = recent <||> weekly <||> monthly


This is almost a valid Haskell program, but: i) I need to import the SnapRotate module, and ii) I don't want to specify a main routine (which looks something like:
main = runPolicy policy

).

So the snaprotate commandline looks almost like runhaskell but does some source file rearranging to address the above two points, and to remove the #! shebang line.
#!/bin/bash
FN=$(mktemp /tmp/snaprotateXXXXX).hs FNHS=$FN.hs
LIBDIR=$(dirname$0)

cat > $FNHS << 32804384892038493284093 import SnapRotate main = runLevels policy 32804384892038493284093 cat$1 | grep --invert-match '^#!' >> $FNHS shift runhaskell -i$LIBDIR $FNHS$@

I wonder if this is the best way to implement such an embedding?

1. It is clearly suboptimal. Your EOF marker of 32804384892038493284093 is not prime.

2. An easier approach is to use literate haskell.

This is common in Setup.lhs files for cabal:

\begin{code}
...
\end{code}

or