我有一个从函数返回的序列(foundApps),我想将一个函数映射到它的所有元素。出于某种原因,apply
和count
适用于sequnece但map
不适用:
(apply println foundApps)
(map println rest foundApps)
(map (fn [app] (println app)) foundApps)
(println (str "Found " (count foundApps) " apps to delete"))))
打印:
{:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(2)>} {:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(4)>}
Found 2 apps to delete for id 1235
所以apply
似乎很乐意为序列工作,但map
却没有。我在哪里傻了?
答案 0 :(得分:32)
很可能你被map
的懒惰所打击。 (map
生成一个惰性序列,只有在某些代码实际使用其元素时才会实现。即使这样,实现也会以块的形式发生,因此您必须遍历整个序列以确保它们都已实现。)尝试将map
表达式包装在dorun
:
(dorun (map println foundApps))
此外,由于您只是为副作用而这样做,因此使用doseq
可能更清晰:
(doseq [fa foundApps]
(println fa))
请注意,(map println foundApps)
应该在REPL中正常工作;我假设你已经从代码中的某个地方提取它,而不是强制它。 doseq
与严格(即不是懒惰)没有任何区别,并且在任何情况下都会为你的论证序列行走。另请注意,doseq
返回nil
作为其值;它只对副作用有益。最后,我从您的代码中跳过了rest
;你可能意味着(rest foundApps)
(除非它只是一个错字)。
另请注意,(apply println foundApps)
会在一行打印所有foundApps
,而(dorun (map println foundApps))
会在自己的行上打印foundApps
的每个成员。
答案 1 :(得分:20)
我有一个简单的解释,这篇文章缺乏。让我们想象一个抽象函数F
和一个向量。所以,
(apply F [1 2 3 4 5])
转换为
(F 1 2 3 4 5)
这意味着F
必须是最好的变量。
虽然
(map F [1 2 3 4 5])
转换为
[(F 1) (F 2) (F 3) (F 4) (F 5)]
这意味着F
必须是单变量的,或至少以这种方式表现。
关于类型有一些细微差别,因为map
实际上返回了一个惰性序列而不是向量。但为了简单起见,我希望它是可以原谅的。
答案 2 :(得分:8)
一点解释可能会有所帮助。通常,您使用apply将一系列元素splat到一组函数的参数中。因此,将函数应用于某些参数只意味着将它们作为参数传递给函数,在单个函数调用中。
map函数将执行您想要的操作,通过将输入的每个元素插入函数然后存储输出来创建新的seq。它虽然懒惰,但是只有在实际迭代列表时才会计算值。要强制执行此操作,您可以使用(doall my-seq)函数,但大多数情况下您不需要这样做。
如果您需要立即执行操作,因为它有副作用,例如打印或保存到数据库或其他东西,那么您通常使用doseq。
所以要将“foo”附加到你的所有应用程序(假设它们是字符串):
(map(fn [app](str app“foo”))found-apps)
或使用shorhand进行匿名函数:
(map#(str%“foo”)found-apps)
执行相同操作但立即打印可以使用以下任一方法完成:
(doall(map#(println%)found-apps))
(doseq [app found-apps](println app))