Mercurial > lasercutter
diff src/clojure/contrib/fcase.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/contrib/fcase.clj Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,108 @@ 1.4 +;;; fcase.clj -- simple variants of "case" for Clojure 1.5 + 1.6 +;; by Stuart Sierra, http://stuartsierra.com/ 1.7 +;; April 7, 2008 1.8 + 1.9 +;; Copyright (c) Stuart Sierra, 2008. All rights reserved. The use 1.10 +;; and distribution terms for this software are covered by the Eclipse 1.11 +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.12 +;; which can be found in the file epl-v10.html at the root of this 1.13 +;; distribution. By using this software in any fashion, you are 1.14 +;; agreeing to be bound by the terms of this license. You must not 1.15 +;; remove this notice, or any other, from this software. 1.16 + 1.17 + 1.18 +;; This file defines a generic "case" macro called "fcase" which takes 1.19 +;; the equality-testing function as an argument. It also defines a 1.20 +;; traditional "case" macro that tests using "=" and variants that 1.21 +;; test for regular expressions and class membership. 1.22 + 1.23 + 1.24 +;; Note (December 23, 2008): This library has been supplanted by the 1.25 +;; inclusion of "condp" in clojure.core as of Clojure SVN rev. 1180. 1.26 + 1.27 + 1.28 +(ns 1.29 + ^{:author "Stuart Sierra", 1.30 + :doc "This file defines a generic \"case\" macro called \"fcase\" which takes 1.31 +the equality-testing function as an argument. It also defines a 1.32 +traditional \"case\" macro that tests using \"=\" and variants that 1.33 +test for regular expressions and class membership. 1.34 + 1.35 + 1.36 +Note (December 23, 2008): This library has been supplanted by the 1.37 +inclusion of \"condp\" in clojure.core as of Clojure SVN rev. 1180."} 1.38 + 1.39 + clojure.contrib.fcase 1.40 + (:refer-clojure :exclude (case))) 1.41 + 1.42 + 1.43 +(defmacro fcase 1.44 + "Generic switch/case macro. 'fcase' is short for 'function case'. 1.45 + 1.46 + The 'compare-fn' is a fn of two arguments. 1.47 + 1.48 + The 'test-expr-clauses' are value-expression pairs without 1.49 + surrounding parentheses, like in Clojure's 'cond'. 1.50 + 1.51 + The 'case-value' is evaluated once and cached. Then, 'compare-fn' 1.52 + is called once for each clause, with the clause's test value as its 1.53 + first argument and 'case-value' as its second argument. If 1.54 + 'compare-fn' returns logical true, the clause's expression is 1.55 + evaluated and returned. If 'compare-fn' returns false/nil, we go to 1.56 + the next test value. 1.57 + 1.58 + If 'test-expr-clauses' contains an odd number of items, the last 1.59 + item is the default expression evaluated if no case-value matches. 1.60 + If there is no default expression and no case-value matches, fcase 1.61 + returns nil. 1.62 + 1.63 + See specific forms of this macro in 'case' and 're-case'. 1.64 + 1.65 + The test expressions in 'fcase' are always evaluated linearly, in 1.66 + order. For a large number of case expressions it may be more 1.67 + efficient to use a hash lookup." 1.68 + [compare-fn case-value & 1.69 + test-expr-clauses] 1.70 + (let [test-val-sym (gensym "test_val") 1.71 + test-fn-sym (gensym "test_fn") 1.72 + cond-loop (fn this [clauses] 1.73 + (cond 1.74 + (>= (count clauses) 2) 1.75 + (list 'if (list test-fn-sym (first clauses) test-val-sym) 1.76 + (second clauses) 1.77 + (this (rest (rest clauses)))) 1.78 + (= (count clauses) 1) (first clauses)))] 1.79 + (list 'let [test-val-sym case-value, test-fn-sym compare-fn] 1.80 + (cond-loop test-expr-clauses)))) 1.81 + 1.82 +(defmacro case 1.83 + "Like cond, but test-value is compared against the value of each 1.84 + test expression with =. If they are equal, executes the \"body\" 1.85 + expression. Optional last expression is executed if none of the 1.86 + test expressions match." 1.87 + [test-value & clauses] 1.88 + `(fcase = ~test-value ~@clauses)) 1.89 + 1.90 +(defmacro re-case 1.91 + "Like case, but the test expressions are regular expressions, tested 1.92 + with re-find." 1.93 + [test-value & clauses] 1.94 + `(fcase re-find ~test-value ~@clauses)) 1.95 + 1.96 +(defmacro instance-case 1.97 + "Like case, but the test expressions are Java class names, tested with 1.98 + 'instance?'." 1.99 + [test-value & clauses] 1.100 + `(fcase instance? ~test-value ~@clauses)) 1.101 + 1.102 +(defn in-case-test [test-seq case-value] 1.103 + (some (fn [item] (= item case-value)) 1.104 + test-seq)) 1.105 + 1.106 +(defmacro in-case 1.107 + "Like case, but test expressions are sequences. The test expression 1.108 + is true if any item in the sequence is equal (tested with '=') to 1.109 + the test value." 1.110 + [test-value & clauses] 1.111 + `(fcase in-case-test ~test-value ~@clauses))