Clojure:组成arity 2(或更高版本)的功能

时间:2015-09-18 10:50:25

标签: clojure functional-programming function-composition arity

我使用可变数量的函数处理数据,具体取决于参数。每个处理函数都将从其前任接收数据,处理它并将其传递给下一个函数。

(defn example [data]
  (do-things-to data))

我的申请流程是

  1. 检查参数并在向量中存储所需的函数
  2. 创建一个包含所有必要步骤的函数
  3. 调用一个包装函数,它执行文件管理并最终应用函数
  4. 样机:

    (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)或类似的序列将需要在许多函数中进行大量重写。

    有什么想法吗?我猜答案是“宏观”,但我从来没有摆弄过这些......

    EDIT1:

    第二个参数是对不断增长的图形数据结构的引用,因此它不需要由函数处理,只是以某种方式传递。 但是这些函数可能来自不同的命名空间,所以我不能简单地将根放在更高的范围内来访问它。全球def是可能的,但非常难看......

    在写这篇文章的时候,我想我可能会在partial之前以某种方式将函数映射到comp

    EDIT2:

    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
    

2 个答案:

答案 0 :(得分:1)

正如您在编辑中提到的那样,您确实可以将您的函数映射到root烘焙过的新函数中:

(mapv #(partial % root) vector-of-functions)

答案 1 :(得分:0)

首先,我觉得这里发生了很多事情:

  1. (filter identity)是一个换能器,但没有说其他fns返回传感器或者包装器是否需要换能器,并且鉴于其中一些将接收两个参数,我们可以放心地说它们不是传感器。您可能需要(partial filter identity)#(filter identity %)

  2. 为什么使用(reduce comp (filter identity) vector-of-functions)代替(apply comp (cons (partial filter identity) vector-of-functions)

  3. 关注如何组合函数,假设其中一些函数接收了更多已经具有该值的参数,则可以使用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])将在应用时返回与(apply comp [fn1 fn2 fn3])相同的结果