The original script is like this:
#lang racket
(for ([i (in-range 3)])
(for ([j (in-range 9)])
(display "X"))
(display "\n"))
(for ([i (in-range 6)])
(for ([j (in-range 3)])
(display " "))
(for ([j (in-range 3)])
(display "X"))
(for ([j (in-range 3)])
(display " "))
(display "\n"))
(for ([i (in-range 3)])
(for ([j (in-range 9)])
(display "X"))
(display "\n"))
The output is:
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
XXX
XXX
XXX
XXX
XXX
XXX
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
I’m wondering whether I can rewrite this using a DSL like this:
(define a
"3 9 X
6 3 b 3 X 3 b
3 9 X")
And then:
(interpret a)
to draw this graph.
Does anyone know what is the best way to do that?
To attack problems like this, first describe a data type that captures the operations you want in your DSL, rather than concentrating on surface syntax. Once you’ve got the data type in hand, you should have a much easier time with the problem.
From a first glance, it looks like we can design 3 fundamental forms in your language:
We can represent this disjoint class with primitive strings and structures. Let’s call this class as a whole a ‘pexpr’, for “printable expr”. In code:
It might help to make some helper functions as abbreviations since “seq” and “repeat” are themselves a bit long-winded.
Your example “I” string can be written as this:
Note that this encoding has an explicit representation for newlines which, from the surface syntax alone, is implicit. It then becomes the job of a parser to take lines in your surface syntax and turning them into pexprs, but that shouldn’t be too difficult. Hopefully. 🙂
Anyway, the interpret function, then, becomes a matter of filling in the details for a template like this:
where the ‘…’s should be easy to fill in.
This approach to these kinds of problems is one described by How to Design Programs and Programming Languages: Application and Interpretation. I’d recommend looking at them: they’re good stuff.