   "Generate alpha-numeric strings."
   (fmap clojure.string/join (vector char-alpha-numeric)))
 
+(defn- +-or---digit?
+  "Returns true if c is \\+ or \\- and d is non-nil and a digit.
+
+  Symbols that start with +3 or -2 are not readable because they look
+  like numbers."
+  [c ^Character d]
+  (core/boolean (and d
+                     (or (= \+ c)
+                         (= \- c))
+                     (Character/isDigit d))))
+
+(def namespace-segment
+  "Generate the segment of a namespace."
+  (->> (tuple char-keyword-first (vector char-keyword-rest))
+       (such-that (fn [[c [d]]] (not (+-or---digit? c d))))
+       (fmap (fn [[c cs]] (clojure.string/join (cons c cs))))))
+
+(def namespace
+  "Generate a namespace (or nil for no namespace)."
+  (->> (vector namespace-segment)
+       (fmap (fn [v] (when (seq v)
+                       (clojure.string/join "." v))))))
+
+(def keyword-segment-rest
+  "Generate segments of a keyword (between \\:)"
+  (->> (tuple char-keyword-rest (vector char-keyword-rest))
+       (fmap (fn [[c cs]] (clojure.string/join (cons c cs))))))
+
+(def keyword-segment-first
+  "Generate segments of a keyword that can be first (between \\:)"
+  (->> (tuple char-keyword-first (vector char-keyword-rest))
+       (fmap (fn [[c cs]] (clojure.string/join (cons c cs))))))
+
 (def keyword
-  "Generate keywords."
-  (->> (tuple char-keyword-first (vector char-keyword-rest))
-       (fmap (fn [[c cs]] (core/keyword (clojure.string/join (cons c cs)))))))
+  "Generate keywords without namespaces."
+  (->> (tuple keyword-segment-first (vector keyword-segment-rest))
+       (fmap (fn [[c cs]]
+               (core/keyword (clojure.string/join ":" (cons c cs)))))))
+
+(def keyword-ns
+  "Generate keywords with optional namespaces."
+  (->> (tuple namespace char-keyword-first (vector char-keyword-rest))
+       (fmap (fn [[ns c cs]]
+               (core/keyword ns (clojure.string/join (cons c cs)))))))
+
+(def char-symbol-first
+  (frequency [[10 char-alpha]
+              [5 char-symbol-special]
+              [1 (return \.)]]))
+
+(def char-symbol-rest
+  (frequency [[10 char-alpha-numeric]
+              [5 char-symbol-special]
+              [1 (return \.)]]))
+
+(def symbol
+  "Generate symbols without namespaces."
+  (frequency [[100 (->> (tuple char-symbol-first (vector char-symbol-rest))
+                        (such-that (fn [[c [d]]] (not (+-or---digit? c d))))
+                        (fmap (fn [[c cs]] (core/symbol (clojure.string/join (cons c cs))))))]
+              [1 (return '/)]]))
+
+(def symbol-ns
+  "Generate symbols with optional namespaces."
+  (frequency [[100 (->> (tuple namespace char-symbol-first (vector char-symbol-rest))
+                        (such-that (fn [[_ c [d]]] (not (+-or---digit? c d))))
+                        (fmap (fn [[ns c cs]] (core/symbol ns (clojure.string/join (cons c cs))))))]
+              [1 (return '/)]]))
 
 (def ratio
   "Generates a `clojure.lang.Ratio`. Shrinks toward 0. Not all values generated

  (:import java.util.Random)
  (:refer-clojure :exclude [int vector list hash-map map keyword
                            char boolean byte bytes sequence
                            not-empty])
  (:require [clojure.core :as core]
            [clojure.test.check.rose-tree :as rose]))


           (such-that (complement zero?) int))))

(def simple-type
  (one-of [int char string ratio boolean keyword keyword-ns symbol symbol-ns]))

(def simple-type-printable
  (one-of [int char-ascii string-ascii ratio boolean keyword keyword-ns symbol symbol-ns]))

(defn container-type
  [inner-type]
