Clojure 使用可变参数
我正在尝试创建自己的reduces实现,到目前为止,我已经有了一个与此测试数据相关的实现:Clojure 使用可变参数,clojure,Clojure,我正在尝试创建自己的reduces实现,到目前为止,我已经有了一个与此测试数据相关的实现: ((fn [func & args] (reduce (fn [acc item] (conj acc (func (last acc) item)) )[(first args)] (first (rest args)))) * 2 [3 4 5] 我不喜欢的是我如何分离ARG 第一个args是我所期望的,即2,但是rest args是[3
((fn [func & args]
(reduce (fn [acc item]
(conj acc (func (last acc) item))
)[(first args)] (first (rest args)))) * 2 [3 4 5]
我不喜欢的是我如何分离ARG
第一个args是我所期望的,即2,但是rest args是[3 4 5],所以我得到了剩余的像这个我不喜欢的第一个rest args
我是否遗漏了一些使使用可变参数更容易的技巧?可变参数只是获取列表中未指定数量的参数,因此所有列表/解构操作都可以在此处应用 例如:
(let [[fst & rst] a-list]
; fst is the first element
; rst is the rest
)
这比:
(let [fst (first a-list)
rst (rest a-list)]
; ...
)
您可以进一步获取列表的第一个和第二个元素,假设它在一行中有>1个元素:
(let [fst snd & rst]
; ...
)
我最初误读了你的问题,以为你在试图重新实现reduce函数。下面是我为这个答案编写的一个示例实现,它不使用first或rest:
我希望它能帮助您了解如何使用列表分解,这可能是您在函数中想要的。这里有一个关于这个主题的例子。可变参数只是获取列表中未指定数量的参数,因此所有列表/解构操作都可以在这里应用 例如:
(let [[fst & rst] a-list]
; fst is the first element
; rst is the rest
)
这比:
(let [fst (first a-list)
rst (rest a-list)]
; ...
)
您可以进一步获取列表的第一个和第二个元素,假设它在一行中有>1个元素:
(let [fst snd & rst]
; ...
)
我最初误读了你的问题,以为你在试图重新实现reduce函数。下面是我为这个答案编写的一个示例实现,它不使用first或rest:
我希望它能帮助您了解如何使用列表分解,这可能是您在函数中想要的。这里有一个关于这个问题的例子。整理一下你的功能
正如@bfontaine所评论的,您可以使用第二个参数而不是第一个rest参数:
这使用
func
第一个args
第二个参数
。。。但是忽略了其他arg
因此,我们可以使用解构来命名args的第一个和第二个元素-init和coll似乎是合适的-giving
(defn reductions [func & [init coll & _]]
(reduce
(fn [acc item] (conj acc (func (last acc) item)))
[init]
coll))
。。。其中u是被忽略参数的常规名称,在本例中为序列
我们可以摆脱它,简化为
(defn reductions [func & [init coll]] ... )
。。。然后去
(defn reductions [func init coll] ... )
…-三个参数的简单函数
处理潜在问题
您的函数有两个问题:
缓慢
缺乏懒惰。
缓慢
此功能中闪烁的红灯表示使用了last in
每次调用时,它都会扫描整个acc,即使acc是一个向量。因此,这种减少所需的时间与coll长度的平方成正比:对于长序列来说,速度太慢了
一个简单的解决方法是用acc dec count acc替换上一个acc,这需要有效的恒定时间
不懒惰
我们仍然不能懒洋洋地使用函数生成的内容。例如,最好像这样封装阶乘序列:
(def factorials (reductions * 1N (next (range)))))
随着你的减少,这个定义永远不会回来
你必须完全重新构造你的函数,使它变得懒惰。让我们修改标准-惰性-缩减以采用解构:
(defn reductions [f init coll]
(cons
init
(lazy-seq
(when-let [[x & xs] (seq coll)]
(reductions f (f init x) xs)))))
现在我们可以定义
(def factorials (reductions * 1N (next (range))))
然后比如说,
(take 10 factorials)
;(1N 1N 2N 6N 24N 120N 720N 5040N 40320N 362880N)
另一种方法是从自身推导序列,就像铁路机车铺设其行驶的轨道一样:
(defn reductions [f init coll]
(let [answer (lazy-seq (reductions f init coll))]
(cons init (map f answer coll))))
但这包含一个对我来说是隐藏的递归,至少:
(nth (reductions * 1N (next (range))) 10000)
;StackOverflowError ...
整理你的功能
正如@bfontaine所评论的,您可以使用第二个参数而不是第一个rest参数:
这使用
func
第一个args
第二个参数
。。。但是忽略了其他arg
因此,我们可以使用解构来命名args的第一个和第二个元素-init和coll似乎是合适的-giving
(defn reductions [func & [init coll & _]]
(reduce
(fn [acc item] (conj acc (func (last acc) item)))
[init]
coll))
。。。其中u是被忽略参数的常规名称,在本例中为序列
我们可以摆脱它,简化为
(defn reductions [func & [init coll]] ... )
。。。然后去
(defn reductions [func init coll] ... )
…-三个参数的简单函数
处理潜在问题
您的函数有两个问题:
缓慢
缺乏懒惰。
缓慢
此功能中闪烁的红灯表示使用了last in
每次调用时,它都会扫描整个acc,即使acc是一个向量。因此,这种减少所需的时间与coll长度的平方成正比:对于长序列来说,速度太慢了
一个简单的解决方法是用acc dec count acc替换上一个acc,这需要有效的恒定时间
不懒惰
我们仍然不能懒洋洋地使用函数生成的内容。例如,最好像这样封装阶乘序列:
(def factorials (reductions * 1N (next (range)))))
随着你的减少,这个定义永远不会回来
你必须完全重新构造你的函数,使它变得懒惰。让我们修改标准-惰性-缩减以采用解构:
(defn reductions [f init coll]
(cons
init
(lazy-seq
(when-let [[x & xs] (seq coll)]
(reductions f (f init x) xs)))))
现在我们可以定义
(def factorials (reductions * 1N (next (range))))
然后比如说,
(take 10 factorials)
;(1N 1N 2N 6N 24N 120N 720N 5040N 40320N 362880N)
另一种方法是从序列本身派生序列,如铁路
铺设其行驶轨道的机车:
(defn reductions [f init coll]
(let [answer (lazy-seq (reductions f init coll))]
(cons init (map f answer coll))))
但这包含一个对我来说是隐藏的递归,至少:
(nth (reductions * 1N (next (range))) 10000)
;StackOverflowError ...
注意你可以使用second:second[3 4 5]是4。你可能会觉得有趣。注意你可以使用second:second[3 4 5]是4。你可能会觉得有趣。