diff src/clojure/contrib/test_contrib/types/examples.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/test_contrib/types/examples.clj	Sat Aug 21 06:25:44 2010 -0400
     1.3 @@ -0,0 +1,152 @@
     1.4 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     1.5 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     1.6 +;;
     1.7 +;; Application examples for data types
     1.8 +;;
     1.9 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    1.10 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    1.11 +
    1.12 +(ns
    1.13 +  #^{:author "Konrad Hinsen"
    1.14 +     :skip-wiki true
    1.15 +     :doc "Examples for data type definitions"}
    1.16 +  clojure.contrib.types.examples
    1.17 +  (:refer-clojure :exclude (deftype))
    1.18 +  (:use [clojure.contrib.types
    1.19 +	 :only (deftype defadt match)])
    1.20 +  (:require [clojure.contrib.generic.collection :as gc])
    1.21 +  (:require [clojure.contrib.generic.functor :as gf]))
    1.22 +
    1.23 +;
    1.24 +; Multisets implemented as maps to integers
    1.25 +;
    1.26 +
    1.27 +; The most basic type definition. A more elaborate version could add
    1.28 +; a constructor that verifies that its argument is a map with integer values.
    1.29 +(deftype ::multiset multiset
    1.30 +  "Multiset (demo implementation)")
    1.31 +
    1.32 +; Some set operations generalized to multisets
    1.33 +; Note that the multiset constructor is nowhere called explicitly, as the
    1.34 +; map operations all preserve the metadata.
    1.35 +(defmethod gc/conj ::multiset
    1.36 +  ([ms x]
    1.37 +   (assoc ms x (inc (get ms x 0))))
    1.38 +  ([ms x & xs]
    1.39 +    (reduce gc/conj (gc/conj ms x) xs)))
    1.40 +
    1.41 +(defmulti union (fn [& sets] (type (first sets))))
    1.42 +
    1.43 +(defmethod union clojure.lang.IPersistentSet
    1.44 +  [& sets]
    1.45 +  (apply clojure.set/union sets))
    1.46 +
    1.47 +; Note: a production-quality implementation should accept standard sets
    1.48 +; and perhaps other collections for its second argument.
    1.49 +(defmethod union ::multiset
    1.50 +  ([ms] ms)
    1.51 +  ([ms1 ms2]
    1.52 +     (letfn [(add-item [ms [item n]]
    1.53 +		       (assoc ms item (+ n (get ms item 0))))]
    1.54 +       (reduce add-item ms1 ms2)))
    1.55 +  ([ms1 ms2 & mss]
    1.56 +     (reduce union (union ms1 ms2) mss)))
    1.57 +
    1.58 +; Let's use it:
    1.59 +(gc/conj #{} :a :a :b :c)
    1.60 +(gc/conj (multiset {}) :a :a :b :c)
    1.61 +
    1.62 +(union #{:a :b} #{:b :c})
    1.63 +(union (multiset {:a 1 :b 1}) (multiset {:b 1 :c 2}))
    1.64 +
    1.65 +;
    1.66 +; A simple tree structure defined as an algebraic data type
    1.67 +;
    1.68 +(defadt ::tree
    1.69 +  empty-tree
    1.70 +  (leaf value)
    1.71 +  (node left-tree right-tree))
    1.72 +
    1.73 +(def a-tree (node (leaf :a) 
    1.74 +		  (node (leaf :b)
    1.75 +			(leaf :c))))
    1.76 +
    1.77 +(defn depth
    1.78 +  [t]
    1.79 +  (match t
    1.80 +    empty-tree  0
    1.81 +    (leaf _)    1
    1.82 +    (node l r)  (inc (max (depth l) (depth r)))))
    1.83 +
    1.84 +(depth empty-tree)
    1.85 +(depth (leaf 42))
    1.86 +(depth a-tree)
    1.87 +
    1.88 +; Algebraic data types with multimethods: fmap on a tree
    1.89 +(defmethod gf/fmap ::tree
    1.90 +  [f t]
    1.91 +  (match t
    1.92 +    empty-tree  empty-tree
    1.93 +    (leaf v)    (leaf (f v))
    1.94 +    (node l r)  (node (gf/fmap f l) (gf/fmap f r))))
    1.95 +
    1.96 +(gf/fmap str a-tree)
    1.97 +
    1.98 +;
    1.99 +; Nonsense examples to illustrate all the features of match
   1.100 +; for type constructors.
   1.101 +;
   1.102 +(defadt ::foo
   1.103 +  (bar a b c))
   1.104 +
   1.105 +(defn foo-to-int
   1.106 +  [a-foo]
   1.107 +  (match a-foo
   1.108 +    (bar x x x)  x
   1.109 +    (bar 0 x y)  (+ x y)
   1.110 +    (bar 1 2 3)  -1
   1.111 +    (bar a b 1)  (* a b)
   1.112 +    :else        42))
   1.113 +
   1.114 +(foo-to-int (bar 0 0 0))    ; 0
   1.115 +(foo-to-int (bar 0 5 6))    ; 11
   1.116 +(foo-to-int (bar 1 2 3))    ; -1
   1.117 +(foo-to-int (bar 3 3 1))    ; 9
   1.118 +(foo-to-int (bar 0 3 1))    ; 4
   1.119 +(foo-to-int (bar 10 20 30)) ; 42
   1.120 +
   1.121 +;
   1.122 +; Match can also be used for lists, vectors, and maps. Note that since
   1.123 +; algebraic data types are represented as maps, they can be matched
   1.124 +; either with their type constructor and positional arguments, or
   1.125 +; with a map template.
   1.126 +;
   1.127 +
   1.128 +; Tree depth once again with map templates
   1.129 +(defn depth
   1.130 +  [t]
   1.131 +  (match t
   1.132 +    empty-tree  0
   1.133 +    {:value _}  1
   1.134 +    {:left-tree l :right-tree r}  (inc (max (depth l) (depth r)))))
   1.135 +
   1.136 +(depth empty-tree)
   1.137 +(depth (leaf 42))
   1.138 +(depth a-tree)
   1.139 +
   1.140 +; Match for lists, vectors, and maps:
   1.141 +
   1.142 +(for [x ['(1 2 3)
   1.143 +	 [1 2 3]
   1.144 +	 {:x 1 :y 2 :z 3}
   1.145 +	 '(1 1 1)
   1.146 +	 [2 1 2]
   1.147 +	 {:x 1 :y 1 :z 2}]]
   1.148 +  (match x
   1.149 +    '(a a a)  	 'list-of-three-equal-values
   1.150 +    '(a b c)  	 'list
   1.151 +    [a a a]   	 'vector-of-three-equal-values
   1.152 +    [a b a]   	 'vector-of-three-with-first-and-last-equal
   1.153 +    [a b c]      'vector
   1.154 +    {:x a :y z}  'map-with-x-equal-y
   1.155 +    {}           'any-map))