        ~(build-map-factory rsym r fields)
        ~r)))
 
-(defmacro defprotocol [psym & doc+methods]
+(defmacro defprotocol
+  "A protocol is a named set of named methods and their signatures:
+
+  (defprotocol AProtocolName
+    ;optional doc string
+    \"A doc string for AProtocol abstraction\"
+
+  ;method signatures
+    (bar [this a b] \"bar docs\")
+    (baz [this a] [this a b] [this a b c] \"baz docs\"))
+
+  No implementations are provided. Docs can be specified for the
+  protocol overall and for each method. The above yields a set of
+  polymorphic functions and a protocol object. All are
+  namespace-qualified by the ns enclosing the definition The resulting
+  functions dispatch on the type of their first argument, which is
+  required and corresponds to the implicit target object ('this' in
+  JavaScript parlance). defprotocol is dynamic, has no special compile-time
+  effect, and defines no new types.
+
+  (defprotocol P
+    (foo [this])
+    (bar-me [this] [this y]))
+
+  (deftype Foo [a b c]
+    P
+    (foo [this] a)
+    (bar-me [this] b)
+    (bar-me [this y] (+ c y)))
+
+  (bar-me (Foo. 1 2 3) 42)
+  => 45
+
+  (foo
+    (let [x 42]
+      (reify P
+        (foo [this] 17)
+        (bar-me [this] x)
+        (bar-me [this y] x))))
+  => 17"
+  [psym & doc+methods]
   (let [p (:name (cljs.analyzer/resolve-var (dissoc &env :locals) psym))
         psym (vary-meta psym assoc :protocol-symbol true)
         ns-name (-> &env :ns :name)

               false)))
         (cljs.core/native-satisfies? ~psym ~xsym)))))

(defmacro lazy-seq [& body]
  `(new cljs.core/LazySeq nil (fn [] ~@body) nil nil))

(defmacro delay [& body]

  (bool-expr (core/list 'js* "typeof ~{} === 'string'" x)))

;; TODO: x must be a symbol, not an arbitrary expression
(defmacro exists?
  "Return true if argument exists, analogous to usage of typeof operator
   in JavaScript."
  [x]
  (bool-expr
    (core/list 'js* "typeof ~{} !== 'undefined'"
      (vary-meta x assoc :cljs.analyzer/no-resolve true))))

(defmacro undefined?
  "Return true if argument is identical to the JavaScript undefined value."
  [x]
  (bool-expr (core/list 'js* "(void 0 === ~{})" x)))

(defmacro identical? [a b]
