Clojure 使用可变参数

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

我正在尝试创建自己的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 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。你可能会觉得有趣。