Clojure:编写 arity 2(或更高)的函数
Clojure: compose functions of arity 2 (or higher)
我正在使用可变数量的函数处理数据,具体取决于参数。每个处理函数都会从其前任函数接收数据,对其进行处理并将其传递给下一个函数。
(defn example [data]
(do-things-to data))
我的申请流程是
- 检查参数并将需要的函数存储在向量中
- 创建一个包含所有必要步骤的函数
- 调用包装函数进行文件管理并最终应用该函数
模型:
(let [my-big-fun (reduce comp (filter identity) vector-of-functions)]
(wrapper lots-a-arguments big-fun)
现在我发现我不仅需要将数据传递给函数,还需要传递另一个数据集。
(defn new-fun-example [root data]
(do-things-to-both root data))
有没有办法做一些类似于我对 arity-1 函数所做的归约?一个简单的 juxt
是行不通的,因为每个函数都会更改下一个函数所需的数据。返回 '(root data)
或类似的序列需要在许多函数中进行大量重写。
有什么想法吗?我猜答案是"macro",但我从来没有摆弄过这些...
编辑 1:
第二个参数是对不断增长的图形数据结构的引用,因此它不需要由函数处理,只是以某种方式传递。
但是这些函数可能来自不同的命名空间,所以我不能简单地将根放在更高的范围内来访问它。全局 def
是可能的,但非常丑陋...
在写这篇文章时,我只是想我可以在 comp
之前以某种方式将函数映射到 partial
。
编辑2:
filter identity
引起了很多混乱,这不是我的问题的一部分。我一开始就不应该将它包含在我的样本中。我按照敏捷的棕色狐狸的建议解决了这个任务,并为有时晦涩难懂而道歉。类似最小解决方案的示例:
(defn example [root data]
(swap! root + data))
(defn fn-chainer [vector-of-functions]
(let [the-root (atom 0)
; this filter step is just required to remove erroneously apperaring nils
; from the vector of functions - not part of the question
vector-of-functions (filter identity vector-of-functions)
; bake the atom to the functions
vector-of-functions (mapv #(partial % the-root) vector-of-functions)
; now chain each funcion's result as argument to the next one
my-big-fun (reduce comp vector-of-functions)]
; let the function chain process some dataset
(my-big-fun 5))
; test some function vectors
(fn-chainer [example])
=> 5 ; = 0 + 5
(fn-chainer [example example])
=> 10 ; = 0 + 5 +5
(fn-chainer [example nil example example nil nil])10
=> 20 ; = 0 + 5 + 5 + 5 + 5, nils removed
首先,我觉得这里发生了很多事情:
(filter identity)
是一个换能器,但没有说明其他 fns return 换能器,或者如果 wrapper 需要一个换能器,并且给定其中一些将接收两个参数,我们可以肯定地说它们不是换能器。您可能想要 (partial filter identity)
或 #(filter identity %)
.
你为什么使用 (reduce comp (filter identity) vector-of-functions)
而不是 (apply comp (cons (partial filter identity) vector-of-functions)
?
考虑到如何组合函数,因为其中一些函数接收到您已有值的更多参数,您可以使用 partial:
(let [root [1 2 3]
other-root [4 5 6]
vector-of-functions [(partial filter identity) example (partial my-fun-example root) (partial other-fun-example root other-root)]
my-big-fun (apply comp vector-of-functions)]
(wrapper lots-a-arguments big-fun))
编辑:我对上面的应用程序使用 reverse
是错误的,(reduce comp [fn1 fn2 fn3])
将 return 与应用 (apply comp [fn1 fn2 fn3])
相同的结果
正如您在编辑中提到的,您确实可以将您的函数映射到 root
内置的新函数中:
(mapv #(partial % root) vector-of-functions)
我正在使用可变数量的函数处理数据,具体取决于参数。每个处理函数都会从其前任函数接收数据,对其进行处理并将其传递给下一个函数。
(defn example [data]
(do-things-to data))
我的申请流程是
- 检查参数并将需要的函数存储在向量中
- 创建一个包含所有必要步骤的函数
- 调用包装函数进行文件管理并最终应用该函数
模型:
(let [my-big-fun (reduce comp (filter identity) vector-of-functions)]
(wrapper lots-a-arguments big-fun)
现在我发现我不仅需要将数据传递给函数,还需要传递另一个数据集。
(defn new-fun-example [root data]
(do-things-to-both root data))
有没有办法做一些类似于我对 arity-1 函数所做的归约?一个简单的 juxt
是行不通的,因为每个函数都会更改下一个函数所需的数据。返回 '(root data)
或类似的序列需要在许多函数中进行大量重写。
有什么想法吗?我猜答案是"macro",但我从来没有摆弄过这些...
编辑 1:
第二个参数是对不断增长的图形数据结构的引用,因此它不需要由函数处理,只是以某种方式传递。
但是这些函数可能来自不同的命名空间,所以我不能简单地将根放在更高的范围内来访问它。全局 def
是可能的,但非常丑陋...
在写这篇文章时,我只是想我可以在 comp
之前以某种方式将函数映射到 partial
。
编辑2:
filter identity
引起了很多混乱,这不是我的问题的一部分。我一开始就不应该将它包含在我的样本中。我按照敏捷的棕色狐狸的建议解决了这个任务,并为有时晦涩难懂而道歉。类似最小解决方案的示例:
(defn example [root data]
(swap! root + data))
(defn fn-chainer [vector-of-functions]
(let [the-root (atom 0)
; this filter step is just required to remove erroneously apperaring nils
; from the vector of functions - not part of the question
vector-of-functions (filter identity vector-of-functions)
; bake the atom to the functions
vector-of-functions (mapv #(partial % the-root) vector-of-functions)
; now chain each funcion's result as argument to the next one
my-big-fun (reduce comp vector-of-functions)]
; let the function chain process some dataset
(my-big-fun 5))
; test some function vectors
(fn-chainer [example])
=> 5 ; = 0 + 5
(fn-chainer [example example])
=> 10 ; = 0 + 5 +5
(fn-chainer [example nil example example nil nil])10
=> 20 ; = 0 + 5 + 5 + 5 + 5, nils removed
首先,我觉得这里发生了很多事情:
(filter identity)
是一个换能器,但没有说明其他 fns return 换能器,或者如果 wrapper 需要一个换能器,并且给定其中一些将接收两个参数,我们可以肯定地说它们不是换能器。您可能想要(partial filter identity)
或#(filter identity %)
.你为什么使用
(reduce comp (filter identity) vector-of-functions)
而不是(apply comp (cons (partial filter identity) vector-of-functions)
?
考虑到如何组合函数,因为其中一些函数接收到您已有值的更多参数,您可以使用 partial:
(let [root [1 2 3]
other-root [4 5 6]
vector-of-functions [(partial filter identity) example (partial my-fun-example root) (partial other-fun-example root other-root)]
my-big-fun (apply comp vector-of-functions)]
(wrapper lots-a-arguments big-fun))
编辑:我对上面的应用程序使用 reverse
是错误的,(reduce comp [fn1 fn2 fn3])
将 return 与应用 (apply comp [fn1 fn2 fn3])
相同的结果
正如您在编辑中提到的,您确实可以将您的函数映射到 root
内置的新函数中:
(mapv #(partial % root) vector-of-functions)