“推敲”这个词来源于唐朝诗人贾岛的故事,说他为诗中的“推”“敲”一字之差,反复思索。数组
Clojure 程序的基础是函数,函数和使用者惟一的合同是它的参数表,咱们 Clojure 对待它也应该有推敲的精神!函数
这看起来是显然的,但咱们常常就在反复改动一个函数实现的时候,忘记检查它有没有没有用的参数。设计
不要为了一个值引入整个结构。例如:code
(defn hello [user] (str "Hello" (:name user)))
这个函数既然只使用 name
,就不如改为这样更精确:ip
(defn hello [name] (str "Hello" name))
这个原则的例外在于,有时为了连续调用,咱们须要一些参数的统一性。这时可使用 destructure 这个强大的语言特性来明示咱们的需求:io
(defn hello [{name :name}] (str "Hello" name))
这样的调用形式既能够知足要求,也更为精确地说明了咱们须要的不是一个特别的 user 的 map,而仅仅是一个有 :name
值的 map。class
所谓“过路参数”:函数对参数值不感兴趣,把他放进参数表仅仅为了调用其余函数。这样的参数在程序中很常见,例如上例中的函数实际就仅仅是 str 函数的包装。即便 name 参数都是过路参数,其实,第二个函数定义写成这样:基础
(def hello (partial str "Hello"))
根本不引入一个额外的参数表更加精确。而最后一种形式写成:cli
(def hello (comp (partial str "Hello") :name))
用函数组合来代替新建函数更为合适。clojure
固然,这条规则实际上用在 hello
这么简单的函数上缺少说明性,咱们用任何一种写法都很容易理解。但是在实际的工做中,随意引入过路参数却会严重影响咱们的大设计。
(defn order-description [{:keys [amount]} username] (let [client-type (if (> amount 10000) "big" "small"] (str (call-name username) " is a " client-type " client."))) (order-description {:amount 15000} "Robert")
这个函数中的 username
又是一个过路参数,它在参数表中出现,将咱们函数实际上仅仅关心 call-name
的结果的逻辑掩盖了起来,而且还形成了咱们对 call-name 这个函数的依赖。改为这样:
(defn order-description [{:keys [amount]} call-name] (let [client-type (if (> amount 10000) "big" "small"] (str call-name " is a " client-type " client."))) (order-description {:amount 15000} (call-name "Robert"))
就将 call-name
的调用责任放在了它的调用者,让 order-description
函数的使用范围更广和更加稳定。