Clojure применить к карте
У меня есть последовательность (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
не работает. Где я глуп?
Ответы
Ответ 1
Скорее всего, вас атакует 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
в своей собственной строке.
Ответ 2
У меня есть простое объяснение, которого нет в этом сообщении. Представьте себе абстрактную функцию 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
фактически возвращает ленивую последовательность вместо вектора. Но для простоты я надеюсь, что это простительно.
Ответ 3
Может помочь небольшое объяснение. В общем случае вы используете применить для разбиения последовательности элементов на набор аргументов функции. Поэтому применение функции к некоторым аргументам просто означает их передачу в качестве аргументов функции в одном вызове функции.
Функция карты сделает то, что вы хотите, создайте новый seq, подключив каждый элемент ввода к функции и затем сохраните вывод. Это делает это лениво, хотя, поэтому значения будут вычисляться только тогда, когда вы на самом деле перебираете список. Для этого вы можете использовать функцию (doall my-seq), но большую часть времени вам это не понадобится.
Если вам нужно выполнить операцию сразу, потому что у нее есть побочные эффекты, такие как печать или сохранение в базе данных или что-то еще, тогда вы обычно используете дозу.
Итак, добавьте "foo" во все ваши приложения (при условии, что они являются строками):
(map (fn [app] (str app "foo" )) found-apps)
или используя shorhand для анонимной функции:
(map # (str% "foo" ) found-apps)
Выполнение такого же действия, но печать сразу может быть выполнена с помощью любого из них:
(doall (map # (println%) found-apps))
(доза [app found-apps] (приложение println))