macrosince v0.0-927imported clojure.core/fnEdit
(fn & sigs)


Defines a function.

name? is an optional name of the function to be used inside body. This is useful for recursive calls. Note that name? in fn is not the same as the name argument to defn, which defines a global symbol for the function.

params* are the arguments to the function and a binding form for the symbols that the arguments will take inside the body of the function. Functions can have arity of 0-20 and there is no runtime enforcement of arity when calling a function (just like in JavaScript).

prepost-map? is an optional map with optional keys :pre and :post that contain collections of pre or post conditions for the function.

body is a series of expressions that execute when the function is called. The arguments to the function are mapped to symbols in params* and are available in body. The value of the last expression in body is the return value of calling the function.

See Also:

Source docstring:
params => positional-params* , or positional-params* & next-param
positional-param => binding-form
next-param => binding-form
name => symbol

Defines a function
Source code @ clojure:src/clj/clojure/core.clj
(defmacro fn
  {:added "1.0", :special-form true,
   :forms '[(fn name? [params* ] exprs*) (fn name? ([params* ] exprs*)+)]}
  [& sigs]
    (let [name (if (symbol? (first sigs)) (first sigs) nil)
          sigs (if name (next sigs) sigs)
          sigs (if (vector? (first sigs)) 
                 (list sigs) 
                 (if (seq? (first sigs))
                   ;; Assume single arity syntax
                   (throw (IllegalArgumentException. 
                            (if (seq sigs)
                              (str "Parameter declaration " 
                                   (first sigs)
                                   " should be a vector")
                              (str "Parameter declaration missing"))))))
          psig (fn* [sig]
                 ;; Ensure correct type before destructuring sig
                 (when (not (seq? sig))
                   (throw (IllegalArgumentException.
                            (str "Invalid signature " sig
                                 " should be a list"))))
                 (let [[params & body] sig
                       _ (when (not (vector? params))
                           (throw (IllegalArgumentException. 
                                    (if (seq? (first sigs))
                                      (str "Parameter declaration " params
                                           " should be a vector")
                                      (str "Invalid signature " sig
                                           " should be a list")))))
                       conds (when (and (next body) (map? (first body))) 
                                           (first body))
                       body (if conds (next body) body)
                       conds (or conds (meta params))
                       pre (:pre conds)
                       post (:post conds)                       
                       body (if post
                              `((let [~'% ~(if (< 1 (count body)) 
                                            `(do ~@body) 
                                            (first body))]
                                 ~@(map (fn* [c] `(assert ~c)) post)
                       body (if pre
                              (concat (map (fn* [c] `(assert ~c)) pre) 
                   (maybe-destructured params body)))
          new-sigs (map psig sigs)]
        (if name
          (list* 'fn* name new-sigs)
          (cons 'fn* new-sigs))
        (meta &form))))