Перепутанный “позволенным” в Clojure

Я только что начал играть с Clojure, и я записал маленький сценарий, чтобы помочь мне понять некоторые функции. Это начинается как это:

(def *exprs-to-test* [  
    "(filter #(< % 3) '(1 2 3 4 3 2 1))"
    "(remove #(< % 3) '(1 2 3 4 3 2 1))"
    "(distinct '(1 2 3 4 3 2 1))"
])

Затем это проходит *exprs-to-test*, оценивает их всех и печатает вывод как это:

(doseq [exstr *exprs-to-test*]
    (do 
        (println "===" (first (read-string exstr)) "=========================")
        (println "Code: " exstr)
        (println "Eval: " (eval (read-string exstr)))
    )
)

Вышеупомянутый код все хорошо работает. Однако (read-string exstr) повторяется так, я пытался использовать let устранить повторение как так:

(doseq [exstr *exprs-to-test*]
    (let [ex (read-string exstr)] (
        (do 
            (println "===" (first ex) "=========================")
            (println "Code: " exstr)
            (println "Eval: " (eval ex))
        )
    ))
)

Но это работает однажды на первый объект в *exprs-to-test*, затем катастрофические отказы с a NullPointerException. Почему имеет дополнение let порождение катастрофического отказа?

5
задан Tom Dalling 7 March 2010 в 03:39
поделиться

3 ответа

У вас есть дополнительный набор скобок вокруг формы do . Ваш код делает следующее:

((do ...))

Он пытается выполнить (как вызов функции) значение всей формы do , но do возвращает nil , поскольку последний println в форме do возвращает nil .

Обратите внимание, ваш стиль отступов нестандартный. Не следует ставить закрывающие скобки на отдельных строках. И let имеет неявный do , поэтому он вам не нужен. Попробуйте это:

user> (doseq [exstr *exprs-to-test*]
        (let [ex (read-string exstr)] 
          (println "===" (first ex) "=========================")
          (println "Code: " exstr)
          (println "Eval: " (eval ex))))
=== filter =========================
Code:  (filter #(< % 3) '(1 2 3 4 3 2 1))
Eval:  (1 2 2 1)
=== remove =========================
Code:  (remove #(< % 3) '(1 2 3 4 3 2 1))
Eval:  (3 4 3)
=== distinct =========================
Code:  (distinct '(1 2 3 4 3 2 1))
Eval:  (1 2 3 4)
7
ответ дан 13 December 2019 в 05:34
поделиться

Брайан уже ответил на ваш вопрос, поэтому я просто хочу дать вам некоторые общие указания для let-form:

1
ответ дан 13 December 2019 в 05:34
поделиться

Я думаю, что другие ответы игнорируют слона в комнате: зачем вы это делаете? В вашем коде есть много вещей, которые заставляют меня беспокоиться, что вы идете по неправильному пути, изучая Clojure:

  • Использование глобальных привязок ( exprs-to-test )
  • Использование DoSq / println последовательное опробование кода
  • Использование eval

Лучший способ изучить API Clojure - использовать REPL. Вы должны настроить свою среду, будь то Vim, Emacs или IDE, чтобы вы могли легко перемещаться между статическим кодом в текстовых файлах и интерактивным REPL. Вот хорошая разбивка ряда IDE Clojure .

Теперь, что касается вашего кода, нужно помнить несколько вещей. Во-первых, почти никогда не бывает веских причин использовать eval. Если вы обнаружите, что делаете это, спросите себя, действительно ли это необходимо. Во-вторых, помните, что Clojure - это функциональный язык, и обычно вам не нужно использовать набор макросов «do». Макросы «do» полезны, когда вам нужно иметь побочные эффекты (в вашем примере побочным эффектом является println to * out *). Наконец, следует избегать использования глобальных переменных. Если вам действительно нужно использовать переменные, вам следует рассмотреть возможность использования макроса привязки для локальной привязки переменных к потоку с неизменяемыми значениями, чтобы не было проблем с параллелизмом.

Я определенно рекомендую вам найти время, чтобы изучить Programming Clojure или другой более подробный справочник по LISP, чтобы по-настоящему понять изменения, необходимые в вашем подходе к программированию для эффективного использования Clojure. Ваш небольшой образец здесь заставляет меня чувствовать, что вы пытаетесь написать империативный код на Clojure, который вообще не будет работать хорошо.

4
ответ дан 13 December 2019 в 05:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: