             [:x] [pred/required-key integer?]
             [:y] [pred/required-key integer?]}))
     
-    (fact "a line has a start and an end, which are points"
-      (subject/canonicalize type-map [:start :end]
-                            {:start (path/includes :Point)
-                             :end (path/includes :Point)})
-      => {[:start] [pred/required-key]
-          [:end] [pred/required-key]
-          [:start :x] [pred/required-key integer?]
-          [:start :y] [pred/required-key integer?]
-          [:end :x] [pred/required-key integer?]
-          [:end :y] [pred/required-key integer?]})
-    
+    (fact "subtypes"
+      (fact "making a colored point by addition"
+        (subject/canonicalize type-map (path/includes :Point) [:color] {:color string?})
+        => {[:color] [pred/required-key string?]
+            [:x] [pred/required-key integer?]
+            [:y] [pred/required-key integer?]}
+        
+        (fact "or you can just merge types"
+          (subject/canonicalize type-map (path/includes :Point) (path/includes :Colored))
+          => {[:color] [pred/required-key string?]
+              [:x] [pred/required-key integer?]
+              [:y] [pred/required-key integer?]})
+        
+        (fact "note that merging an optional type doesn't make it required"
+          (subject/canonicalize type-map (path/includes :Point) (path/includes :OptionalColored))
+          => {[:color] [string?]
+              [:x] [pred/required-key integer?]
+              [:y] [pred/required-key integer?]}))
+      
+      (fact "a line has a start and an end, which are points"
+        (subject/canonicalize type-map [:start :end]
+                              {:start (path/includes :Point)
+                               :end (path/includes :Point)})
+        => {[:start] [pred/required-key]
+            [:end] [pred/required-key]
+            [:start :x] [pred/required-key integer?]
+            [:start :y] [pred/required-key integer?]
+            [:end :x] [pred/required-key integer?]
+            [:end :y] [pred/required-key integer?]})
+      
     (fact "a figure has a color and a set of points"
       (subject/canonicalize type-map [:points]
                             {[:points ALL] (path/includes :Point)}

      => {[:points] [pred/required-key]
          [:points ALL :color] [pred/required-key string?]
          [:points ALL :x] [pred/required-key integer?]
          [:points ALL :y] [pred/required-key integer?]})))


;;;; Let us not forget the simple cases

(fact "simple maps just have their keys and values vectorized"
  (subject/canonicalize ..t.. {:a even?}) => {[:a] [even?]}
  (subject/canonicalize ..t.. {:a even?, :b even?})
  => {[:a] [even?]
      [:b] [even?]})

(fact "simple vectors"
  (subject/canonicalize ..t.. [:a :b]) => {[:a] [pred/required-key]
                                           [:b] [pred/required-key]})
  

;;;; Canonicalize - random examples, probably redundant

(fact "already vectorized keys and values are left alone if flat"
  (subject/canonicalize ..t.. {[:a] even?}) => {[:a] [even?]}
  (subject/canonicalize ..t.. {[:a] [even?]}) => {[:a] [even?]}
  (subject/canonicalize ..t.. {[:a :b] even?}) => {[:a :b] [even?]})
  
(fact "forks are allowed in vectors"
  (subject/canonicalize ..t.. {[:a [:b1 :b2]] even?})
  => {[:a :b1] [even?]

    (fact "this is a pretty unlikely map to use, but it will work"
      (subject/canonicalize ..t..
                            {:points {ALL {:x integer?
                                           :y integer?}}})
      => {[:points ALL :x] [integer?]
          [:points ALL :y] [integer?]}))
)



(facts "About type-map and path merging"

  (fact "multiple arguments are allowed"
    (subject/canonicalize ..t.. {:a pred/required-key} {:b pred/required-key})
    => {[:a] [pred/required-key]
        [:b] [pred/required-key]})
  
  (fact "arguments with the same keys have their values merged"
    (subject/canonicalize ..t.. {:a pred/required-key} {:a even?})
    => {[:a] [pred/required-key even?]}
    (subject/canonicalize ..t..
                          {:a {:b pred/required-key}}
                          {:a map?}
                          {:a {:b even?}})
    => {[:a] [map?]
        [:a :b] [pred/required-key even?]})

  (fact "maps and vectors can be merged"
    (subject/canonicalize ..t.. [ :a :b ] {:a even?})
    => {[:a] [pred/required-key even?]
        [:b] [pred/required-key]})

  (fact "nested and unnested elements can be combined"
    (subject/canonicalize ..t.. (path/requires :a [:b :c] :d)) => {[:a] [pred/required-key]
                                                                   [:b :c] [pred/required-key]
                                                                   [:d] [pred/required-key]})
  (fact "note that forks allow the possibility of duplicate paths"
    (subject/canonicalize ..t.. {[:a :b1] pos?
                                 [:a [:b1 :b2]] even?})
    => (just {[:a :b1] (just [(exactly pos?) (exactly even?)] :in-any-order)
              [:a :b2] [even?]})
    
    (subject/canonicalize ..t.. {[:a :b] pos?
                                 [:a] {:b even?}})
    => (just {[:a :b] (just [(exactly pos?) (exactly even?)] :in-any-order)})))
  

(facts "Some typical uses of a type-map"
  (let [type-map (-> {}
                     (assoc :Point (subject/canonicalize ..t.. [:x :y]
                                                         {:x integer? :y integer?})
                            :Colored (subject/canonicalize ..t.. [:color]
                                                           {:color string?})
                            :OptionalColored (subject/canonicalize ..t.. 
                                                                   {:color string?})))]
    (fact "merging types"
      (fact "making a colored point by addition"
        (subject/canonicalize type-map (path/includes :Point) [:color] {:color string?})
        => {[:color] [pred/required-key string?]
            [:x] [pred/required-key integer?]
            [:y] [pred/required-key integer?]})
      
      (fact "or you can just merge types"
        (subject/canonicalize type-map (path/includes :Point) (path/includes :Colored))
