【问题标题】:Am I reinventing the (squared) wheel?我在重新发明(平方)轮子吗?
【发布时间】:2011-04-08 16:11:21
【问题描述】:

我们应该知道,Clojure 的map 可以应用于序列:

(map #(* %1 %1) [1 2 3])           ; (1)

..或不止一个,这样:

(map vector [0 1] [2 1])           ; (2)
;=> ([0 2] [1 1])

现在我想获得与 (2) 相同的结果,但我将参数存储在一个序列中。换句话说,以下内容不会给出预期的结果:

(map vector [[0 1] [2 1]])         ; (3)
;=> ([[0 1]] [[2 1]])

所以我写了这个简单的宏,其中 umap 代表“unsplice map”:

(defmacro umap [fun args-list]
  "umap stands for unspliced map.
  Let args-list be a list of args [a1 a2 ... an].
  umap is the same of (map fun a1 a2 .. an)"
  `(map ~fun ~@args-list))

显然它就像一个魅力:

(umap vector [[0 1] [2 1]])        ; (4)
;=> ([0 2] [1 1])

所以这是我的问题:我是在重新发明轮子吗? 是否有其他方法可以与(4)相同?

提前谢谢你,

阿尔弗雷多

【问题讨论】:

    标签: macros map clojure


    【解决方案1】:

    apply 解包参数列表末尾序列中的所有元素。

    user> (apply map vector [[0 1] [2 1]])
    ([0 2] [1 1])
    

    【讨论】:

    • 谢谢,我确信我在重新发明轮子 :)
    【解决方案2】:

    你的umap 的作用并不明显。实际上,只有在编译时将参数向量作为文字时它才会起作用 - 这正是您可以将多个参数传递给 map 的时间!

    user> (umap vector [[1 2] [1 2]])
    ([1 1] [2 2])
    user> (let [args [[1 2] [1 2]]]
            (umap vector args))
    java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
    [Thrown class java.lang.RuntimeException]
    

    宏只能访问符号args,因为它是在编译时运行的,不能拼接以使用map。正确的答案是使用apply,它将其最后一个参数视为一个序列,并将其拼接成给定函数的一系列附加参数:

    user> (let [args [[1 2] [1 2]]]
            (apply map vector args))
    ([1 1] [2 2])
    

    【讨论】:

    • 感谢 amalloy,您的回答总是有用的!
    【解决方案3】:

    我是否遗漏了什么,或者mapcat 是否可以满足您的需求?

    【讨论】:

    • 您一定遗漏了什么,但我不确定是什么。 mapcat 并没有让他更接近解决他的问题。
    • 啊,好的。我想我现在明白了我所缺少的。
    猜你喜欢
    • 1970-01-01
    • 2011-03-02
    • 2012-09-01
    • 1970-01-01
    • 2014-08-06
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 2011-09-04
    相关资源
    最近更新 更多