Mat*_*ick 12 clojure variadic-functions
这是我在Clojure中遇到的一个问题:
user=> (max [3 4 5 6 7])
[3 4 5 6 7] ; expected '7'
Run Code Online (Sandbox Code Playgroud)
有些功能不符合我的期望!
这是一个解决方案apply:
user=> (apply max [3 4 5 6 7])
7
Run Code Online (Sandbox Code Playgroud)
其他例子是concat,和min.
我的问题,作为一个Clojure新手,为什么这些函数是可变的?我希望他们对序列进行操作.使用apply最佳/惯用的方式来获得我想要的东西?
注意: 我并不是说拥有可变函数或者有更好的方法是不好的.我只是想知道是否遵循规则或惯例,或者我是否应该注意这种方法是否具有特定优势.
编辑:我认为原来的问题不清楚.这就是我的意思:
在我使用的其他编程语言中,有类似monoid的操作,例如添加数字,查找更大的元素,连接列表.
这些操作通常有两个用例:
1)使用接受两个参数的函数组合两个元素
2)使用接受元素列表(或序列)的函数组合0到n个元素
可以根据第一种情况(通常使用reduce)构建第二种情况的功能.
但是,Clojure增加了第三个用例:
3)使用可变参数函数组合0到n个元素
所以问题是,为什么Clojure会添加第三个案例?
保罗的回答表明:
Pau*_*aul 15
1)方便. 使用数学函数,+当您尝试进行一些计算时将序列中的所有内容包装起来会很烦人.
2)效率.使用集合/序列包装所有内容也会效率低下,首先需要创建序列,然后需要在运行时解压缩而不是在编译时查找正确的Java函数.
3)期望.这就是这些函数在其他Lisps中的工作方式,以及在其他函数式语言中使用稍微不同的语法,因此对于来到Clojure的人来说是合理的期望.我会说,在其他函数式语言中应用诸如+序列之类的函数的惯用方法是使用reduce或者foldl/ foldr,所以这也符合Clojure处理它的方式.
4)灵活性.事实上这些函数可以与更高阶函数一起使用,例如,map如果它们是可变参数,则使它们更方便使用.假设您有三个向量,并且您希望将函数应用于同一位置的元素.如果你的函数是可变参数,那么你可以只使用带有多个集合的map(map也必须是variadic然后;)):
(map + [1 2 3 4] [2 3 4 5] [3 4 5 6])
; [6 9 12 15]
Run Code Online (Sandbox Code Playgroud)
如果所有这些函数只是采集集合,那么这比你将要的方便得多.
习惯用法:(kotarak的优秀评论后编辑)
如果你应该使用reduce或取决于功能apply.
对于数学函数(+,-,*,/,etc.)在Java世界中采用2个参数reduce更有意义,因为它可以直接使用2参数Java版本.apply它们有点隐式执行reduce(函数添加两个参数然后重复结果,下一个参数和其余的.这几乎是减少的.)
对于str使用apply可能更有效.当str使用多个参数调用它时,它会创建一个StringBuilder,将所有参数添加到它,然后创建一个字符串.使用reduceStringBuilder将创建n-1次,每次只添加一个字符串.这就像画家笑话中的Shlemiel一样,导致O(n ^ 2)的复杂性.
到目前为止的判决:使用apply数学函数不会造成太大伤害,但使用reduce它str可能相当昂贵.