Created
February 28, 2020 18:54
-
-
Save boxxxie/fb4aa4c2b4a427175ae599e3a5d97768 to your computer and use it in GitHub Desktop.
clojure.core.match+ (adding elixir style guards)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns loco.match | |
(:require [meander.epsilon :as m :refer [match]] | |
[clojure.walk :as walk])) | |
;;TODO: add this syntax to defun, and improve arglists | |
(defn guards-to-map | |
"transforms a single matching clause (with new :guard syntax) into supported syntax | |
e.g.: [sym _] :guard [sym [pred1 pred2]] return" | |
([matcher return] (list matcher return)) | |
([matcher _ guards return] | |
(let [guards-map (->> guards | |
(partition 2) | |
(mapcat (fn [[term guard]] | |
(if (sequential? term) | |
(map (fn [term] [term (list term :guard guard)]) term) | |
[[term (list term :guard guard)]]))) | |
(into {})) | |
matcher-update (walk/postwalk-replace guards-map matcher)] | |
(list | |
(if (empty matcher) ;;handle single-expressions | |
(into (empty matcher) matcher-update) | |
matcher-update) | |
return)))) | |
(defn guard-syntax | |
"allow for support of 4 arity match syntax | |
e.g.: [sym _] :guard [sym [pred1 pred2]] return" | |
[match-rows] | |
(let [transformed-guards (->> match-rows | |
(partition 2) | |
(reduce | |
(fn [acc matcher-pair] | |
(let [previous (peek acc)] | |
(if (and (= 2 (count previous)) (= :guard (second previous))) | |
(-> acc | |
pop | |
(conj (concat previous matcher-pair))) | |
(conj acc matcher-pair)))) | |
[]) | |
(mapcat (fn [match-tuple] | |
(apply guards-to-map match-tuple))) | |
)] | |
transformed-guards)) | |
(defmacro match+ [match-on & match-rows] | |
`(match ~match-on | |
~@(guard-syntax match-rows))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns loco.match-test | |
(:use loco.match | |
clojure.test) | |
(:require [meander.epsilon :as m :refer [match]])) | |
(deftest match+test | |
(is (= | |
(match 1 | |
a 2) | |
(match+ 1 | |
a 2))) | |
(is (= (match 1 | |
a a) | |
(match+ 1 | |
a a))) | |
(is (= (match 1 | |
(b :guard integer?) :return) | |
(match+ 1 | |
b :guard [b integer?] :return))) | |
(is (= (match {:d 1} | |
{:d (d :guard integer?)} d) | |
(match+ {:d 1} | |
{:d d} :guard [d [integer?]] d))) | |
(is (= (match {:d {:a 1}} | |
{:d {:a (d :guard integer?)}} d) | |
(match+ {:d {:a 1}} | |
{:d {:a d}} :guard [d integer?] d))) | |
(is (= (match [1 [1]] | |
[(a :guard integer?) [(b :guard integer?)]] a) | |
(match+ [1 [1]] | |
[a [b]] :guard [a integer? | |
b integer?] a))) | |
(is (= (match [1 1 2 2 ] | |
[(a :guard integer?) (b :guard integer?) | |
(c :guard [integer? even?]) (d :guard [integer? even?])] a) | |
(match+ [1 1 2 2] | |
[a b c d] :guard [[a b] integer? | |
[c d] [integer? even?]] a)) | |
"should be able to express shared guards") | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment