4

我无法弄清楚如何将一些简单的代码抽象为循环/映射/for结构。我有以下代码有效,因为它给了我想要的输出:

(let    
    [recipe [1 1 2] 
    voicing [0 2 4]
    counts (range (count voicing))
    scale C]
    (map vector
        (make-scale recipe voicing scale 0)
        (make-scale recipe voicing scale 1)
        (make-scale recipe voicing scale 2)
    )

输出是:

 ([:C :E :G] [:D :F :B] [:E :A :C] [:G :B :D] [:A :C :F] [:B :E :G] [:D :F :A])

我基本上使用“(map vector arg1 arg2 ...)”调用来交错3个seq。

显然,我需要做最后一步,删除重复的 make-scale 调用。问题是,我需要:

 (map vector arg1 arg2 arg2)

以及我知道如何使用循环的所有方式都给了我在 seq 中循环的结果:

 (map vector (arg1 arg2 arg3))

重构初始代码的最佳方法是什么,以便我只有一个函数调用来进行缩放?

4

1 回答 1

3

我认为您正在寻找:

(apply map vector (map (partial make-scale recipe voicing scale) [0 1 2]))

通常,apply只要您有一个序列并希望将其元素用作函数的连续参数,它就会有所帮助。您还可以将一些参数添加到列表中(在这种情况下,vector参数作为第一个参数添加到map.)

在 Clojure 中,许多 stdlib 函数需要一个扩展列表(vector几乎所有其他集合构造函数,str。)我认为这是设计使然 - 您应该apply与它们一起使用。

所讨论的序列甚至可以是无限的(即惰性无限),当然,如果正在应用的函数处理惰性无限参数列表。这工作正常,即使concat被应用于列表的无限列表:

(take 7 (apply concat (cycle [[1 2 3]])))
>>> (1 2 3 1 2 3 1)
于 2012-05-05T20:15:41.610 回答