Nullpointer в clojure при выполнении doseq с несколькими выражениями в теле

Другая возможность могла бы состоять в том, чтобы использовать XmlReader и проверить на ошибочное количество> 0. Что-то вроде этого:

    void CheckXml()
    {
        string _xmlFile = "this.xml";
        string _xsdFile = "schema.xsd"; 
        StringCollection _xmlErrors = new StringCollection();

        XmlReader reader = null;
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ValidationEventHandler += new ValidationEventHandler(this.ValidationEventHandler);
        settings.ValidationType = ValidationType.Schema;
        settings.IgnoreComments = chkIgnoreComments.Checked;
        settings.IgnoreProcessingInstructions = chkIgnoreProcessingInstructions.Checked;
        settings.IgnoreWhitespace = chkIgnoreWhiteSpace.Checked;
        settings.Schemas.Add(null, XmlReader.Create(_xsdFile));
        reader = XmlReader.Create(_xmlFile, settings);
        while (reader.Read())
        {
        }
        reader.Close();
        Assert.AreEqual(_xmlErrors.Count,0);
    }    

    void ValidationEventHandler(object sender, ValidationEventArgs args)
    {
        _xmlErrors.Add("<" + args.Severity + "> " + args.Message);
    }
5
задан Hans Sjunnesson 7 October 2009 в 09:39
поделиться

2 ответа

Ну, вы уже выяснили решение, поэтому всего несколько подсказок, чтобы объяснить поведение:

В Clojure (как и в Lisp, Scheme и т. Д.) Все является выражением, а выражение - либо атомом, либо списком. Что касается списков, руководство Clojure говорит

, что непустые списки считаются вызовами. в специальные формы, макросы или функции. Звонок имеет вид (операнды оператора *).

В вашем примере тело ((println x) (println x)) представляет собой список, а сам оператор является выражением, которое Clojure должно вычислить для получения фактического оператор. То есть вы говорите: «Оцените первое выражение и возьмите его возвращаемое значение как функцию для вызова второго выражения». Однако println возвращает, как вы заметили, только nil . Это приводит к исключению NullPointerException , если nil интерпретируется как оператор.

Ваш код работает с (do (println x) (println x)) , потому что do - это специальная форма, которая оценивает каждое выражение по очереди и возвращает значение последнего выражения. Здесь do - это оператор, а выражения с println - это операнды.

Чтобы понять полезность такого поведения, обратите внимание, что функции являются первоклассными объектами в Clojure, например, вы можете вернуть функцию как результат другой функции. Например, возьмите следующий код:

(doseq [x '(1 2 3 4)] ((if (x > 2)
    (fn [x] (println (+ x 2)))
    (fn [x] (println (* x 3)))) x))

Здесь я динамически выясняю, какой оператор будет вызывать элемент в последовательности. Сначала вычисляется if -выражение. Если x больше двух, if вычисляется как функция, которая печатает x + 2 , в противном случае вычисляется функция, выводящая x * 3 . Затем эта функция применяется к x последовательности.

обратите внимание, что в Clojure функции являются объектами первого класса, например, вы можете вернуть функцию в результате другой функции. Например, возьмите следующий код:

(doseq [x '(1 2 3 4)] ((if (x > 2)
    (fn [x] (println (+ x 2)))
    (fn [x] (println (* x 3)))) x))

Здесь я динамически выясняю, какой оператор будет вызывать элемент в последовательности. Сначала вычисляется if -выражение. Если x больше двух, if вычисляется как функция, которая печатает x + 2 , в противном случае вычисляется функция, выводящая x * 3 . Затем эта функция применяется к x последовательности.

обратите внимание, что в Clojure функции являются объектами первого класса, например, вы можете вернуть функцию в результате другой функции. Например, возьмите следующий код:

(doseq [x '(1 2 3 4)] ((if (x > 2)
    (fn [x] (println (+ x 2)))
    (fn [x] (println (* x 3)))) x))

Здесь я динамически выясняю, какой оператор будет вызывать элемент в последовательности. Сначала вычисляется if -выражение. Если x больше двух, if вычисляется как функция, которая печатает x + 2 , в противном случае вычисляется функция, выводящая x * 3 . Затем эта функция применяется к x последовательности.

вычисляется if -выражение. Если x больше двух, if вычисляется как функция, которая печатает x + 2 , в противном случае вычисляется функция, выводящая x * 3 . Затем эта функция применяется к x последовательности.

вычисляется if -выражение. Если x больше двух, if вычисляется как функция, которая печатает x + 2 , в противном случае вычисляется функция, выводящая x * 3 . Затем эта функция применяется к x последовательности.

10
ответ дан 18 December 2019 в 11:58
поделиться

Я вижу, что вы уже осознали проблему, однако обратите внимание, что вам не нужно делать:

(doseq [x '(1 2 3 4)] (println x) (println "x"))

Doseq (как следует из названия) уже выполняет:)

5
ответ дан 18 December 2019 в 11:58
поделиться
Другие вопросы по тегам:

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