|
229 | 229 | ;; Monadic Let Macro
|
230 | 230 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
231 | 231 |
|
| 232 | +(defn- flatten-bindings |
| 233 | + [bindings] |
| 234 | + (filterv symbol? (tree-seq coll? seq bindings))) |
| 235 | + |
| 236 | +(defn- parse-step |
| 237 | + [[l r] fn-bindings fn-sym] |
| 238 | + (case l |
| 239 | + :let |
| 240 | + (let [normalized-bindings (flatten-bindings (conj fn-bindings (take-nth 2 r)))] |
| 241 | + [`(let ~r (~fn-sym ~@normalized-bindings)) normalized-bindings]) |
| 242 | + :when |
| 243 | + (let [normalized-bindings (flatten-bindings fn-bindings)] |
| 244 | + [`(bind (guard ~r) (partial ~fn-sym ~@normalized-bindings)) (conj normalized-bindings '_)]) |
| 245 | + (let [normalized-bindings (flatten-bindings fn-bindings)] |
| 246 | + [`(bind ~r (partial ~fn-sym ~@normalized-bindings)) (conj normalized-bindings l)]))) |
| 247 | + |
232 | 248 | #?(:clj
|
233 | 249 | (defmacro mlet
|
234 | 250 | "Monad composition macro that works like Clojure's
|
|
258 | 274 | (not-empty bindings)
|
259 | 275 | (even? (count bindings)))
|
260 | 276 | (throw (IllegalArgumentException. "bindings has to be a vector with even number of elements.")))
|
261 |
| - (->> (reverse (partition 2 bindings)) |
262 |
| - (reduce (fn [acc [l r]] |
263 |
| - (case l |
264 |
| - :let `(let ~r ~acc) |
265 |
| - :when `(bind (guard ~r) |
266 |
| - (fn [~(gensym)] ~acc)) |
267 |
| - `(bind ~r (fn [~l] ~acc)))) |
268 |
| - `(do ~@body))))) |
| 277 | + (let [first-sym (gensym) |
| 278 | + [let-body new-fn-bindings] (parse-step (take 2 bindings) [] first-sym)] |
| 279 | + (loop [rem-bindings (next (partition 2 bindings)) |
| 280 | + current-sym first-sym |
| 281 | + fn-bindings new-fn-bindings |
| 282 | + new-bindings []] |
| 283 | + (if (empty? rem-bindings) |
| 284 | + (list 'let (into [] cat [[current-sym `(fn ~'_ ~(conj ['&] fn-bindings) ~@body)] new-bindings]) let-body) |
| 285 | + (let [new-sym (gensym) |
| 286 | + [expr new-fn-bindings] (parse-step (first rem-bindings) fn-bindings new-sym)] |
| 287 | + (recur (next rem-bindings) |
| 288 | + new-sym |
| 289 | + new-fn-bindings |
| 290 | + (into [] cat [[current-sym `(fn ~'_ ~(conj ['&] fn-bindings) ~expr)] new-bindings])))))))) |
269 | 291 |
|
270 | 292 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
271 | 293 | ;; Applicative Let Macro
|
|
0 commit comments