Function 如何在Clojure中为函数参数创建默认值

Function 如何在Clojure中为函数参数创建默认值,function,clojure,default-value,optional-parameters,Function,Clojure,Default Value,Optional Parameters,我带着这个: (defn string->integer [str & [base]] (Integer/parseInt str (if (nil? base) 10 base))) (string->integer "10") (string->integer "FF" 16) (定义字符串->整数[str&[base]] (整数/parseInt str(if(nil?base)10 base))) (字符串->整数“10”) (字符串->整数“FF”16) 但这一定是一种更好的方法

我带着这个:

(defn string->integer [str & [base]] (Integer/parseInt str (if (nil? base) 10 base))) (string->integer "10") (string->integer "FF" 16) (定义字符串->整数[str&[base]] (整数/parseInt str(if(nil?base)10 base))) (字符串->整数“10”) (字符串->整数“FF”16)
但这一定是一种更好的方法。

如果签名的算术性不同,则函数可以有多个签名。您可以使用它来提供默认值

(defn string->integer 
  ([s] (string->integer s 10))
  ([s base] (Integer/parseInt s base)))

请注意,假设
false
nil
都被视为非值,
(if(nil?base)10 base)
可以缩短为
(if base 10)
,或者进一步缩短为
(或base 10)
,也可以将
rest
参数作为Clojure 1.2[]以来的映射进行分解。这允许您命名函数参数并为其提供默认值:

(defn string->integer [s & {:keys [base] :or {base 10}}]
    (Integer/parseInt s base))
现在你可以打电话了

(string->integer "11")
=> 11


您可以在这里看到这一点:(例如)

此解决方案更接近原始解决方案的精神,但稍微干净一些

(defn string->integer [str & [base]]
  (Integer/parseInt str (or base 10)))
类似的模式可以方便地使用
let

(defn string->integer [str & [base]]
  (let [base (or base 10)]
    (Integer/parseInt str base)))
虽然在本例中更详细,但如果希望使用依赖于其他输入值的默认值,则它可能会很有用。例如,考虑以下函数:

(defn exemplar [a & [b c]]
  (let [b (or b 5)
        c (or c (* 7 b))]
    ;; or whatever yer actual code might be...
    (println a b c)))

(exemplar 3) => 3 5 35
(partial string->integer 10)
这种方法可以很容易地扩展到命名参数的工作中(如M.Gilliar的解决方案):

或者使用更多的融合:

(defn exemplar [a & {:keys [b c] :or {b 5}}]
  (let [c (or c (* 7 b))]
    (println a b c)))

您可能还需要考虑另一种方法:函数。可以说,这是为函数指定默认值的更“实用”和更灵活的方法

首先创建(如有必要)一个函数,该函数包含要作为默认参数提供的参数作为前导参数:

之所以这样做,是因为Clojure版本的
partial
允许您仅按照“默认”值在函数定义中出现的顺序提供这些值。根据需要对参数进行排序后,您可以使用
partial
函数创建函数的“默认”版本:

(defn exemplar [a & [b c]]
  (let [b (or b 5)
        c (or c (* 7 b))]
    ;; or whatever yer actual code might be...
    (println a b c)))

(exemplar 3) => 3 5 35
(partial string->integer 10)
为了使此函数可多次调用,您可以使用
def
将其放入变量中:

(def decimal (partial string->integer 10))
(decimal "10")
;10
您还可以使用
let
创建“本地默认值”:

(let [hex (partial string->integer 16)]
  (* (hex "FF") (hex "AA")))
;43350
与其他方法相比,部分函数方法有一个关键优势:函数的使用者仍然可以决定默认值,而不是函数的生产者,而无需修改函数定义。这在示例中用
hex
进行了说明,我已经确定默认函数
decimal
不是我想要的

这种方法的另一个优点是,您可以为默认函数指定不同的名称(十进制、十六进制等),这可能更具描述性和/或不同的范围(var、local)。如果需要,也可以将部分功能与上述一些方法混合使用:

(defn string->integer 
  ([s] (string->integer s 10))
  ([base s] (Integer/parseInt s base)))

(def hex (partial string->integer 16))

(请注意,这与Brian的回答略有不同,因为参数的顺序已被颠倒,原因如下)

您还可以查看
(fnil)

与Matthew的建议非常相似的方法是不执行
&
rest参数,但要求调用方提供灵活(可选)键的单个额外map参数

(defn string->integer[s{:keys[base]:或{base 10}]
(整数/解数基数)
(字符串->整数“11”{:基数8})
=> 9
(字符串->整数“11”{})
=> 11
这样做有一个好处,即选项是一个单参数映射,调用者在传递偶数个额外参数时不必如此小心。此外,这种风格的衣料可以做得更好。编辑器还应该更好地使用映射键值表格式对齐(如果您对此感兴趣的话),而不是每行一对参数

稍微有点不好的一面是,在没有选项的情况下调用时,仍然必须提供一个空映射

这一点在本文(代码)中有所涉及


更新:Clojure 1.11现在支持(使用
&
)。

如果来自Python背景,那么很容易理解:)这比公认的答案更容易理解……这是公认的方式吗?请考虑加入这份文件。我必须使用非官方风格指南来帮助解决这个问题。这个答案更有效地捕捉到比接受的答案更合适的方式,尽管两者都会很好。(当然,Lisp语言的一个强大功能是通常有许多不同的方法来完成相同的基本任务)这在我看来有点冗长,我有一段时间难以记住它,所以我创建了。如果您不需要依赖于其他默认值的默认值(或者即使您需要),上面Matthew的解决方案还允许为不同的变量设置多个默认值。它比使用常规的
要干净得多,我是Clojure noob,所以也许OpenLearner是对的,但这是一个有趣的替代Matthew上面的解决方案。我很高兴知道这一点,不管我最终是否决定使用它。
不同于
:或
,因为
不知道
@XiangruLian的区别。你是说当使用时:或者,如果你传递假,它将知道使用假而不是默认值?当传递false而不是false时,它会使用默认值吗?我认为第二行最好说
(重复s10)
,而不是重复函数名
string->integer
。这将使将来重命名函数更容易。有人知道在这些情况下不使用
recur
的原因吗?看起来
recur
只能在相同的算术上工作。如果您在上面尝试了recur,例如:
java.lang.IllegalArgumentException:要recur的参数计数不匹配,应为:1个参数,得到:2,编译:
运行到相同的
(defn string->integer 
  ([s] (string->integer s 10))
  ([base s] (Integer/parseInt s base)))

(def hex (partial string->integer 16))