Ошибка утверждения в макросе deftest Clojure при сравнении списков

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

Сначала сообщаемое сообщение:

FAIL in (to-symbol-list-test) (util_test.clj: 105)
ожидается: (= (цитата (a (не b) c)) (список символов ["a" "(не b)" "c"]))
фактический: (не (= (a (не b) c) (a (не b) c)))

Но очевидно, что вместо (= (a (не b) c) (a (не b) c)) следует указывать значение true.

Второй конкретный код теста:

(deftest to-symbol-list-test 
(is (= '(a (not b) c) (to-symbol-list ["a" "(not b)" "c"]))))

Третье определение списка символов:

(defn to-symbol-list [term]
  "Converts a vector based term into a list based term
  by converting its elements into symbols recursivly"
  (postwalk
    #(if (string? %)
       (symbol %)
       (reverse (into '() %)))
    term))

Функция даже должна конвертировать вложенные векторы. Это пример, другие функции ведут себя таким же образом. Я догадался, что это может быть вызвано разными типами. Например, list vs lazy-seq и я сравниваю ленивую функцию вместо данных, но типы, похоже, правильные. В REPL я получаю:

(type (to-symbol-list ["a" "(not b)" "c"]))
=> clojure.lang.PersistentList

2 ответа

Решение

to-symbol-list возвращает список из 3 символов и не рекурсивно обрабатывает вложенную структуру данных. К сожалению, второй символ печатает так же, как и правильно проанализированная структура данных, которую вы ожидаете. Я думаю, что в этом случае вам лучше использовать clojure.edn/read-string ( документы здесь), которые проанализируют вашу структуру данных, как я думаю, вы ожидаете.

(defn to-symbol-list [list-of-strings]
  (map edn/read-string list-of-strings))

(to-symbol-list ["a" "(not b)" "c"])

Кроме того, в качестве подсказки для диагностики подобных вещей в будущем, вы можете передать дополнительный аргумент clojure.test/is который будет распечатан в случае сбоя. Это может быть результатом вызова функции, например:

(ns to-symbols-test
  (:require [clojure.edn :as edn]
            [clojure.test :refer [deftest is are testing] :as t]
            [clojure.data :as data]
            [clojure.pprint :as pp]))

(defn to-symbol-list [l]
  (map edn/read-string l))

(defn diff [a b]
  (with-out-str (pp/pprint (take 2 (data/diff a b)))))

(deftest test-to-symbol-list
  (testing "to-symbol-list should convert recursively"
    (let [expected '(a (not b) c)
          result   (to-symbol-list ["a" "(not b)" "c"])]
      (is (= expected result (diff expected result))))))

Кажется, что to-symbol-list витки "(not b)" строка символа, но не вложенный список. Чтобы это исправить, вам нужно будет реорганизовать эту функцию, чтобы учесть парены. Скажи если видит ( как первый символ строки, он вызывает себя рекурсивно, добавляя результат в какой-то аккумулятор (кстати, SICP полон таких упражнений).

Другие вопросы по тегам