Подтвердить что ты не робот

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 не работает. Где я глуп?

4b9b3361

Ответ 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))