annotate 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
rev   line source
rlm@10 1 ;;; fcase.clj -- simple variants of "case" for Clojure
rlm@10 2
rlm@10 3 ;; by Stuart Sierra, http://stuartsierra.com/
rlm@10 4 ;; April 7, 2008
rlm@10 5
rlm@10 6 ;; Copyright (c) Stuart Sierra, 2008. All rights reserved. The use
rlm@10 7 ;; and distribution terms for this software are covered by the Eclipse
rlm@10 8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
rlm@10 9 ;; which can be found in the file epl-v10.html at the root of this
rlm@10 10 ;; distribution. By using this software in any fashion, you are
rlm@10 11 ;; agreeing to be bound by the terms of this license. You must not
rlm@10 12 ;; remove this notice, or any other, from this software.
rlm@10 13
rlm@10 14
rlm@10 15 ;; This file defines a generic "case" macro called "fcase" which takes
rlm@10 16 ;; the equality-testing function as an argument. It also defines a
rlm@10 17 ;; traditional "case" macro that tests using "=" and variants that
rlm@10 18 ;; test for regular expressions and class membership.
rlm@10 19
rlm@10 20
rlm@10 21 ;; Note (December 23, 2008): This library has been supplanted by the
rlm@10 22 ;; inclusion of "condp" in clojure.core as of Clojure SVN rev. 1180.
rlm@10 23
rlm@10 24
rlm@10 25 (ns
rlm@10 26 ^{:author "Stuart Sierra",
rlm@10 27 :doc "This file defines a generic \"case\" macro called \"fcase\" which takes
rlm@10 28 the equality-testing function as an argument. It also defines a
rlm@10 29 traditional \"case\" macro that tests using \"=\" and variants that
rlm@10 30 test for regular expressions and class membership.
rlm@10 31
rlm@10 32
rlm@10 33 Note (December 23, 2008): This library has been supplanted by the
rlm@10 34 inclusion of \"condp\" in clojure.core as of Clojure SVN rev. 1180."}
rlm@10 35
rlm@10 36 clojure.contrib.fcase
rlm@10 37 (:refer-clojure :exclude (case)))
rlm@10 38
rlm@10 39
rlm@10 40 (defmacro fcase
rlm@10 41 "Generic switch/case macro. 'fcase' is short for 'function case'.
rlm@10 42
rlm@10 43 The 'compare-fn' is a fn of two arguments.
rlm@10 44
rlm@10 45 The 'test-expr-clauses' are value-expression pairs without
rlm@10 46 surrounding parentheses, like in Clojure's 'cond'.
rlm@10 47
rlm@10 48 The 'case-value' is evaluated once and cached. Then, 'compare-fn'
rlm@10 49 is called once for each clause, with the clause's test value as its
rlm@10 50 first argument and 'case-value' as its second argument. If
rlm@10 51 'compare-fn' returns logical true, the clause's expression is
rlm@10 52 evaluated and returned. If 'compare-fn' returns false/nil, we go to
rlm@10 53 the next test value.
rlm@10 54
rlm@10 55 If 'test-expr-clauses' contains an odd number of items, the last
rlm@10 56 item is the default expression evaluated if no case-value matches.
rlm@10 57 If there is no default expression and no case-value matches, fcase
rlm@10 58 returns nil.
rlm@10 59
rlm@10 60 See specific forms of this macro in 'case' and 're-case'.
rlm@10 61
rlm@10 62 The test expressions in 'fcase' are always evaluated linearly, in
rlm@10 63 order. For a large number of case expressions it may be more
rlm@10 64 efficient to use a hash lookup."
rlm@10 65 [compare-fn case-value &
rlm@10 66 test-expr-clauses]
rlm@10 67 (let [test-val-sym (gensym "test_val")
rlm@10 68 test-fn-sym (gensym "test_fn")
rlm@10 69 cond-loop (fn this [clauses]
rlm@10 70 (cond
rlm@10 71 (>= (count clauses) 2)
rlm@10 72 (list 'if (list test-fn-sym (first clauses) test-val-sym)
rlm@10 73 (second clauses)
rlm@10 74 (this (rest (rest clauses))))
rlm@10 75 (= (count clauses) 1) (first clauses)))]
rlm@10 76 (list 'let [test-val-sym case-value, test-fn-sym compare-fn]
rlm@10 77 (cond-loop test-expr-clauses))))
rlm@10 78
rlm@10 79 (defmacro case
rlm@10 80 "Like cond, but test-value is compared against the value of each
rlm@10 81 test expression with =. If they are equal, executes the \"body\"
rlm@10 82 expression. Optional last expression is executed if none of the
rlm@10 83 test expressions match."
rlm@10 84 [test-value & clauses]
rlm@10 85 `(fcase = ~test-value ~@clauses))
rlm@10 86
rlm@10 87 (defmacro re-case
rlm@10 88 "Like case, but the test expressions are regular expressions, tested
rlm@10 89 with re-find."
rlm@10 90 [test-value & clauses]
rlm@10 91 `(fcase re-find ~test-value ~@clauses))
rlm@10 92
rlm@10 93 (defmacro instance-case
rlm@10 94 "Like case, but the test expressions are Java class names, tested with
rlm@10 95 'instance?'."
rlm@10 96 [test-value & clauses]
rlm@10 97 `(fcase instance? ~test-value ~@clauses))
rlm@10 98
rlm@10 99 (defn in-case-test [test-seq case-value]
rlm@10 100 (some (fn [item] (= item case-value))
rlm@10 101 test-seq))
rlm@10 102
rlm@10 103 (defmacro in-case
rlm@10 104 "Like case, but test expressions are sequences. The test expression
rlm@10 105 is true if any item in the sequence is equal (tested with '=') to
rlm@10 106 the test value."
rlm@10 107 [test-value & clauses]
rlm@10 108 `(fcase in-case-test ~test-value ~@clauses))