## Wednesday, 7 January 2015

### Maya- A DSL for math and numerical work

I feel awkward writing mathematical functions as s-exps
``````
(let [d (* 4 a c),
D (Math/sqrt (- (* b b) d)),
t (* 2 a), -b (- b)]
[(/ (+ -b D) t)
(/ (- -b D) t)]))
```
```

Clojure's thread-first macro eases the pain a bit..

``````
(let [d (* 4 a c),
D (-> (* b b) (- d) Math/sqrt),
t (* 2 a), -b (- b)]
[(-> -b (+ D) (/ t))
(-> -b (- D) (/ t))]))
```
```

..but it's still pretty loaded with parens, and not very clear.

We need a math DSL that looks infixy and uses fewer parens.
Luckily, we can hack one for ourselves in no time.

~*~

``````
(defmacro math->
"(math-> 1 + 5 * 2 / 3) ;=> (-> 1 (+ 5) (* 2) (/ 3)) ;=> 4"
[exp & f-x-pairs]
(if (even? (count f-x-pairs))
`(-> ~exp
~@(for [[f x] (partition 2 f-x-pairs)]
(list f x)))
(throw (Exception. "f-x-pairs should be even."))))
```

Step 2- Allow temporary bindings

```
(defmacro maya
"(maya 1 + 5 :as six, six * 2 :as twelve, twelve / 3 * 2) ;=> 8"
[& exprs]
(let [[exp [_ ?as & next-exprs :as E]] (split-with #(not= :as %) exprs)]
(if (empty? E)
(cons `math-> exp)
`(let [~?as (math-> ~@exp)]
(maya ~@next-exprs)))))
```

Step 3- Profit?

```
``````
(maya 4 * a * c :as d,
b * b - d -> Math/sqrt :as D,
2 * a :as t, (- b) :as -b,
-b + D / t :as x1,
-b - D / t :as x2,
[x1 x2]))
```
```

~*~

Edit: Here's the original gist.