Почему мой код печатается не так, как должен? - PullRequest
7 голосов
/ 08 сентября 2011

Я пытаюсь создать для в Clojure.

Я следую шпаргалке с сайта Clojure .

например:

(take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))

Я пытаюсь создать свой собственный for, который должен печатать "Hello World" 100 раз.

(take 100 (for [a (range 100) 
      :while (< a 100)] 
    (println "Hello World")
    )
)

По какой-то причине он не печатает Hello World 100 раз.Почему нет?

Ответы [ 3 ]

12 голосов
/ 08 сентября 2011

Самое важное, что вам нужно знать, это то, что последовательности в Clojure ленивы. Это означает, что элементы в последовательности оцениваются только тогда, когда они необходимы. Это позволяет работать с бесконечными последовательностями.

В большинстве случаев это именно то, что вам нужно, но это может сбивать с толку, когда вы на самом деле не интересуетесь значениями элементов последовательности, но побочными эффектами функций, которые создают элементы последовательности. В вашем примере последовательность состоит из 100 возвращаемых значений функции println, то есть 100 раз nil - не очень интересно. Но у функции println есть побочный эффект печати «Hello World» на стандартный вывод.

Проблема в том, что если вы никогда ничего не делаете с элементами в последовательности, функции println никогда не оцениваются и строки не печатаются. Это вроде работает в REPL, потому что P в REPL означает print - возвращаемое значение выражения, которое вы ввели, печатается. Чтобы напечатать всю последовательность, она должна быть оценена, поэтому вы видите кучу «Hello World», но также и кучу nils. Если вы запустите код вне REPL (без использования возвращаемого значения), вы не увидите Hello Worlds.

Если вас интересуют побочные эффекты ваших функций создания предметов, вы можете использовать doall или doseq. doall заставляет всю последовательность быть оцененной и возвращает ее:

(doall (for [a (range 100)] (println "Hello World")))

doseq не возвращает последовательность (возвращается nil) и имеет синтаксис, такой как for:

(doseq [a (range 100)] (println "Hello World"))

Также обратите внимание, что вам действительно нужно указать желаемое количество (100) только один раз. Функция range уже создает последовательность из 100 элементов. Предложение :while в вашем коде является избыточным, равно как и функция take (получение первых 100 элементов из последовательности, содержащей 100 элементов, мало что дает).

Надеюсь, это поможет!

2 голосов
/ 08 сентября 2011

попробуйте добавить doall впереди: функция для создает ленивую последовательность, как и take .Они могут не оценить, пока вы не добавите doall .

Эта небольшая причуда - обычное раздражение в Clojure, но имеет смысл, когда вы освоитесь с "ленивым мышлением".

1 голос
/ 08 сентября 2011

На самом деле, это работает для меня. В последнем примере печатает сто "Hello World", но take получает только сто nil с, также напечатанных в REPL. Первый пример работает как есть:

user=> (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y])) ([1 0] [2 0] [2 1] [3 0] [3 1] [3 2] [4 0] [4 1] [4 2] [4 3] [5 0] [5 1] [5 2] [5 3] [5 4] [6 0] [6 1] [6 2] [6 3] [6 4] [6 5] [7 0] [7 1] [7 2] [7 3] [7 4] [7 5] [7 6] [8 0] [8 1] [8 2] [8 3] [8 4] [8 5] [8 6] [8 7] [9 0] [9 1] [9 2] [9 3] [9 4] [9 5] [9 6] [9 7] [9 8] [10 0] [10 1] [10 2] [10 3] [10 4] [10 5] [10 6] [10 7] [10 8] [10 9] [11 0] [11 1] [11 2] [11 3] [11 4] [11 5] [11 6] [11 7] [11 8] [11 9] [11 10] [12 0] [12 1] [12 2] [12 3] [12 4] [12 5] [12 6] [12 7] [12 8] [12 9] [12 10] [12 11] [13 0] [13 1] [13 2] [13 3] [13 4] [13 5] [13 6] [13 7] [13 8] [13 9] [13 10] [13 11] [13 12] [14 0] [14 1] [14 2] [14 3] [14 4] [14 5] [14 6] [14 7] [14 8])

Для фактической печати вы можете попробовать более простой цикл:

(dotimes [i 100] (println "Hello World"))

Наконец, если вы используете for, вам не нужен :while, так как диапазон уже содержит 100 элементов:

(take 100 (for [a (range 100)] 
               (println "Hello World")))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...