Clojure适用于地图

Jam*_*sey 30 clojure

我有一个从函数返回的序列(foundApps),我想将一个函数映射到它的所有元素.由于某种原因,applycount为sequnece工作,但map没有:

(apply println foundApps)
(map println rest foundApps)
(map (fn [app] (println app)) foundApps)
(println (str "Found " (count foundApps) " apps to delete"))))
Run Code Online (Sandbox Code Playgroud)

打印:

{: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
Run Code Online (Sandbox Code Playgroud)

所以apply似乎很乐意为序列工作,但map事实并非如此.我在哪里傻?

Mic*_*zyk 33

很可能你会受到map懒惰的打击.(map产生一个懒惰的序列,只有在某些代码实际使用其元素时才会实现.即使这样,实现也会以块的形式发生,因此您必须遍历整个序列以确保它们都已实现.)尝试将map表达式包装在一个dorun:

(dorun (map println foundApps))
Run Code Online (Sandbox Code Playgroud)

此外,由于您只是为了副作用,所以使用它可能更干净doseq:

(doseq [fa foundApps]
  (println fa))
Run Code Online (Sandbox Code Playgroud)

请注意,(map println foundApps)在REPL 中应该可以正常工作; 我假设你已经从代码中的某个地方提取它,而不是强制它.没有这样的差别doseq是严格的(即不是懒惰的),并且在任何情况下都会为你提供它的参数序列.还要注意doseq返回nil值作为其值; 它只对副作用有益.最后我跳过rest你的代码; 你可能有意思(rest foundApps)(除非它只是一个错字).

另请注意,(apply println foundApps)foundApps在一行上打印所有内容,而(dorun (map println foundApps))foundApps在其自己的行上打印每个成员.

  • `dorun`和`doall`有区别吗? (4认同)

ris*_*hat 22

我有一个简单的解释,这篇文章缺乏.让我们想象一个抽象函数F和一个向量.所以,

(apply F [1 2 3 4 5])
Run Code Online (Sandbox Code Playgroud)

翻译成

(F 1 2 3 4 5)
Run Code Online (Sandbox Code Playgroud)

这意味着F必须是最好的变量.

(map F [1 2 3 4 5])
Run Code Online (Sandbox Code Playgroud)

翻译成

[(F 1) (F 2) (F 3) (F 4) (F 5)]
Run Code Online (Sandbox Code Playgroud)

这意味着F必须是单变量,或者至少表现得这样.

关于类型有一些细微差别,因为map实际上返回一个惰性序列而不是向量.但为了简单起见,我希望它是可以原谅的.

  • 适用于地图的重要解释.在其他一些动态编程语言中有适用名称的名称,它被称为splatting或unpacking. (5认同)
  • 感谢您提供简单的概念性答案! (3认同)
  • 现在我的生活更简单了。谢谢 (: (2认同)

ros*_*ejn 8

一点点解释可能有所帮助.通常,您使用apply将一系列元素splat到一组函数的参数中.因此,将函数应用于某些参数只是意味着在单个函数调用中将它们作为参数传递给函数.

map函数将执行您想要的操作,通过将输入的每个元素插入函数然后存储输出来创建新的seq.它虽然懒惰,但是只有在实际迭代列表时才会计算值.要强制执行此操作,您可以使用(doall my-seq)函数,但大多数情况下您不需要这样做.

如果您需要立即执行操作,因为它有副作用,如打印或保存到数据库或其他东西,那么您通常使用doseq.

因此,要将"foo"附加到您的所有应用程序(假设它们是字符串):

(地图(fn [app](str app"foo"))found-apps)

或使用shorhand进行匿名功能:

(地图#(str%"foo")found-apps)

执行相同操作但立即打印可以使用以下任一方法完成:

(doall(地图#(println%)found-apps))

(doseq [app found-apps](println app))