2013-08-26 76 views
7

我是一个新手,Clojure的,我想知道如果有一种方法来定义可以这样调用函数:与关键字参数可变参数功能

(strange-adder 1 2 3 :strange true) 

也就是说,一个函数,它可以接收可变数量的整数和关键字参数。

我知道我可以定义关键字参数的函数是这样的:

(defn strange-adder 
    [a b c & {:keys [strange]}] 
    (println strange) 
    (+ a b c)) 

但现在我的功能只能接收整数的固定数量。

有没有办法同时使用两种样式?

回答

8

不幸的是,没有。

解构运算符&在参数列表中使用后面的所有内容,因此它无法处理一个形式的两组不同的变量解构组。

一种选择是将功能分成几个部分。虽然这只适用于你可以安排它,所以只有其中一个是可变的(使用&)。更普遍和不太方便的解决方案是将整个参数列表视为一个可变参数,并从手动开始选择数字。

user> (defn strange-adder 
     [& args] 
     (let [nums (take-while number? args) 
       opts (apply hash-map (drop-while number? args)) 
       strange (:strange opts)] 
      (println strange) 
       (apply + nums))) 
#'user/strange-adder 
user> (strange-adder 1 2 3 4 :strange 4) 
4 
10 
1

没有正式的支持,我知道的,但这样的事情应该是可行的:

(defn strange-adder 
    [& args] 
    (if (#{:strange} (-> args butlast last)) 
    (do (println (last args)) 
     (apply + (drop-last 2 args))) 
    (apply + args))) 

我不知道这是否可以推广(检查关键字如何扩大到任意数量的最终参数?)。一种选择可能是将所有选项放在散列表中作为最后一个参数,并检查最后一个参数是否为散列表(但对于某些函数来说,这些函数可能会是hashmaps的任意参数)。

4

移动可变参数部分到参数列表的尾部,并传递选项作为地图:

(defn strange-adder [{:keys [strange]} & nums] 
    (println strange) 
    (apply + nums)) 

(strange-adder {:strange true} 1 2 3 4 5)