Печать внутри для цикла - PullRequest
0 голосов
/ 23 марта 2019

Я практиковал один урок Clojure и должен был убедиться, что цикл for был выполнен, поэтому я поместил туда команду println, но она не отображала сообщения.

Так что теперь у меня возник вопрос...

Этот код печатает имя Тома:

(ns tutorial.core)
(defn -main []
  (println 'Jane)
  (for [a ['Tom]]
    (println a))
;;    'Kate
)



tutorial.core> (-main)
Jane
Tom
(nil)
tutorial.core> 

, но это не так:

(ns tutorial.core)
(defn -main []
  (println 'Jane)
  (for [a ['Tom]]
    (println a))
    'Kate
)


tutorial.core> (-main)
Jane
Kate
tutorial.core>

Почему?В каких случаях мы можем ожидать, что println не будет печатать тексты?

Ответы [ 2 ]

1 голос
/ 25 марта 2019

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

Если вы хотите использовать цикл for, вы можете удалить лень, поместив его в выражение (vec ...), что приведет к немедленному запуску цикла for. Таким образом, мы получаем:

(println :start)
(vec
  (for [a [1 2 3]]
    (println a)))
(println :end)

с результатом:

:start
1
2
3
:end

Без vec мы получаем поведение, которое вы видели:

(println :start)
(for [a [1 2 3]]
  (println a))
(println :end)

с результатом:

:start
:end

Я почти никогда не хочу ленивых результатов, так как неопределенность, связанная с при вычислении, может затруднить отладку. Я использую приведенную выше конструкцию так часто, что написал небольшой макрос forv, который всегда возвращает векторный результат, аналогично функции mapv.

1 голос
/ 24 марта 2019

for - это не цикл, это понимание последовательности, которая возвращает ленивую последовательность. Следовательно, ваше выражение for будет выполнять свои побочные эффекты (вызовы println) только при оценке возвращенной последовательности. REPL оценивает значения, возвращаемые вашими вызовами, в -main, поэтому он может их распечатать.

Ваш первый пример возвращает ленивую последовательность, которая оценивается REPL, вызывая оценку вызова (println 'Tom). Поскольку println возвращает nil, результирующая последовательность содержит одно значение nil - это (nil), которое вы видите в выводе.

Ваш второй пример создает ту же последовательность, но не оценивает ее, вместо этого 'Kate возвращается из функции, и REPL печатает это.

Если вам нужен императив для цикла, вы должны использовать doseq:

(defn -main []
  (println 'Jane)
  (doseq [a ['Tom]]
    (println a))
  'Kate)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...