2010-02-22 2 views
28

У меня есть последовательность (foundApps), возвращаемая функцией, и я хочу сопоставить функцию со всеми ее элементами. По какой-то причине, applycount и работа для sequnece но map не:Clojure apply vs 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 не делает. Где я глуп?

ответ

31

Скорее всего, вы попадаете на лень map. (map создает ленивую последовательность, которая реализуется только тогда, когда какой-то код фактически использует свои элементы. И даже тогда реализация происходит в кусках, так что вам нужно пройти всю последовательность, чтобы убедиться, что все это реализовано.) Попробуйте обернуть выражение map в dorun:

(dorun (map println foundApps)) 

Кроме того, так как вы делаете это только для побочных эффектов, это может быть чище использовать doseq вместо:

(doseq [fa foundApps] 
    (println fa)) 

Обратите внимание, что (map println foundApps) должна хорошо работать на РЕПЛ; Я предполагаю, что вы извлекли его где-то в своем коде, где его не принуждают. Нет такой разницы с doseq, которая является строгой (т. Е. Не ленивой) и будет вызывать последовательности аргументов для вас при любых обстоятельствах. Также обратите внимание, что doseq возвращает nil в качестве значения; это полезно только для побочных эффектов. Наконец, я пропустил rest из вашего кода; вы, возможно, имели в виду (rest foundApps) (если только это не опечатка).

Также отметим, что (apply println foundApps) будет печатать все foundApps на одной линии, в то время как (dorun (map println foundApps)) будет печатать каждый член foundApps по своей линии.

+3

Есть ли разница между 'dorun' и' doall'? –

8

Немного объяснения могут помочь. В общем случае вы используете применить для разбиения последовательности элементов на набор аргументов функции. Поэтому применение функции к некоторым аргументам просто означает их передачу в качестве аргументов функции в одном вызове функции.

Функция карты будет делать то, что вы хотите, создать новый seq, подключив каждый элемент ввода к функции, а затем сохраните вывод. Это делает это лениво, хотя, поэтому значения будут вычисляться только тогда, когда вы на самом деле перебираете список. Для этого вы можете использовать функцию (doall my-seq), но большую часть времени вам это не понадобится.

Если вам необходимо выполнить операцию немедленно, потому что она имеет побочные эффекты, такие как печать или сохранение в базе данных или что-то еще, тогда вы обычно используете дозу.

Так, чтобы добавить "Foo" для всех ваших приложений (при условии, что они являются строками):

(карта (сноска [приложение] (ул приложение "Foo")) найдено-приложений)

или с помощью shorhand для анонимной функции:

(карта # (ул% "Foo") найдено-приложений)

Проделав то же самое, но сразу печать может быть сделано с любым из них:

(DOALL (карта # (Println%) найдено-приложений))

(doseq [приложение найдено-приложений] (Println приложение))

13

У меня есть простое объяснение, которое не имеет этого сообщения. Представим абстрактную функцию F и вектор. Так,

(apply F [1 2 3 4 5]) 

переводит

(F 1 2 3 4 5) 

, что означает, что F должен быть в лучшем случае VARIADIC.

В то время как

(map F [1 2 3 4 5]) 

переводит к

[(F 1) (F 2) (F 3) (F 4) (F 5)] 

, что означает, что F должен быть одной переменной, или по крайней мере ведут себя подобным образом.

Существует несколько нюансов о типах, поскольку map фактически возвращает ленивую последовательность вместо вектора. Но ради простоты, надеюсь, это простительно.

+0

Благодарим вас за простой концептуальный ответ! – JaKXz

+3

Отличное объяснение применения к карте. Существует название того, что применяется в некоторых других языках динамического программирования, оно называется splatting или распаковкой. – blushrt

+0

Теперь моя жизнь проще. Спасибо (: – stryku