Mercurial > lasercutter
view 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 source
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3 ;;4 ;; Application examples for data types5 ;;6 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9 (ns10 #^{:author "Konrad Hinsen"11 :skip-wiki true12 :doc "Examples for data type definitions"}13 clojure.contrib.types.examples14 (:refer-clojure :exclude (deftype))15 (:use [clojure.contrib.types16 :only (deftype defadt match)])17 (:require [clojure.contrib.generic.collection :as gc])18 (:require [clojure.contrib.generic.functor :as gf]))20 ;21 ; Multisets implemented as maps to integers22 ;24 ; The most basic type definition. A more elaborate version could add25 ; a constructor that verifies that its argument is a map with integer values.26 (deftype ::multiset multiset27 "Multiset (demo implementation)")29 ; Some set operations generalized to multisets30 ; Note that the multiset constructor is nowhere called explicitly, as the31 ; map operations all preserve the metadata.32 (defmethod gc/conj ::multiset33 ([ms x]34 (assoc ms x (inc (get ms x 0))))35 ([ms x & xs]36 (reduce gc/conj (gc/conj ms x) xs)))38 (defmulti union (fn [& sets] (type (first sets))))40 (defmethod union clojure.lang.IPersistentSet41 [& sets]42 (apply clojure.set/union sets))44 ; Note: a production-quality implementation should accept standard sets45 ; and perhaps other collections for its second argument.46 (defmethod union ::multiset47 ([ms] ms)48 ([ms1 ms2]49 (letfn [(add-item [ms [item n]]50 (assoc ms item (+ n (get ms item 0))))]51 (reduce add-item ms1 ms2)))52 ([ms1 ms2 & mss]53 (reduce union (union ms1 ms2) mss)))55 ; Let's use it:56 (gc/conj #{} :a :a :b :c)57 (gc/conj (multiset {}) :a :a :b :c)59 (union #{:a :b} #{:b :c})60 (union (multiset {:a 1 :b 1}) (multiset {:b 1 :c 2}))62 ;63 ; A simple tree structure defined as an algebraic data type64 ;65 (defadt ::tree66 empty-tree67 (leaf value)68 (node left-tree right-tree))70 (def a-tree (node (leaf :a)71 (node (leaf :b)72 (leaf :c))))74 (defn depth75 [t]76 (match t77 empty-tree 078 (leaf _) 179 (node l r) (inc (max (depth l) (depth r)))))81 (depth empty-tree)82 (depth (leaf 42))83 (depth a-tree)85 ; Algebraic data types with multimethods: fmap on a tree86 (defmethod gf/fmap ::tree87 [f t]88 (match t89 empty-tree empty-tree90 (leaf v) (leaf (f v))91 (node l r) (node (gf/fmap f l) (gf/fmap f r))))93 (gf/fmap str a-tree)95 ;96 ; Nonsense examples to illustrate all the features of match97 ; for type constructors.98 ;99 (defadt ::foo100 (bar a b c))102 (defn foo-to-int103 [a-foo]104 (match a-foo105 (bar x x x) x106 (bar 0 x y) (+ x y)107 (bar 1 2 3) -1108 (bar a b 1) (* a b)109 :else 42))111 (foo-to-int (bar 0 0 0)) ; 0112 (foo-to-int (bar 0 5 6)) ; 11113 (foo-to-int (bar 1 2 3)) ; -1114 (foo-to-int (bar 3 3 1)) ; 9115 (foo-to-int (bar 0 3 1)) ; 4116 (foo-to-int (bar 10 20 30)) ; 42118 ;119 ; Match can also be used for lists, vectors, and maps. Note that since120 ; algebraic data types are represented as maps, they can be matched121 ; either with their type constructor and positional arguments, or122 ; with a map template.123 ;125 ; Tree depth once again with map templates126 (defn depth127 [t]128 (match t129 empty-tree 0130 {:value _} 1131 {:left-tree l :right-tree r} (inc (max (depth l) (depth r)))))133 (depth empty-tree)134 (depth (leaf 42))135 (depth a-tree)137 ; Match for lists, vectors, and maps:139 (for [x ['(1 2 3)140 [1 2 3]141 {:x 1 :y 2 :z 3}142 '(1 1 1)143 [2 1 2]144 {:x 1 :y 1 :z 2}]]145 (match x146 '(a a a) 'list-of-three-equal-values147 '(a b c) 'list148 [a a a] 'vector-of-three-equal-values149 [a b a] 'vector-of-three-with-first-and-last-equal150 [a b c] 'vector151 {:x a :y z} 'map-with-x-equal-y152 {} 'any-map))