Clojure: Lein запустить не удалось разрешить символ

Я только начал свой первый проект clojure, используя lein, код здесь:

(ns fileops.core
  (:use
    [clojure.core :only (slurp)]
    [clojure-csv.core :only (parse-csv)]
    [fileops.core]))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (read-file "sample.csv"))

(defn read-file
  "open and read the csv file"
  [fname]
  (with-open [file (clojure.java.io/reader fname)]
    (parse-csv (slurp fname))))

Я попытался запустить это с помощью "lein run", но я продолжаю получать эту ошибку:

Caused by: java.lang.RuntimeException: Unable to resolve symbol: read-file in this context
    at clojure.lang.Util.runtimeException(Util.java:219)
    at clojure.lang.Compiler.resolveIn(Compiler.java:6874)
    at clojure.lang.Compiler.resolve(Compiler.java:6818)
    at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6779)
    at clojure.lang.Compiler.analyze(Compiler.java:6343)
    ... 52 more

Что я делаю неправильно?

Ответ 1

Вы использовали только slurp из ядра clojure, что означает, что любая другая основная функция теперь недоступна для вас:) Попробуйте изменить ns, чтобы использовать :require вместо :use, поскольку это более идиоматично.

Следует отметить, что порядок имеет значение в clojure, поэтому, если вы не объявляете функцию в верхней части вашего файла, как на C и некоторых других языках, более ранние функции не смогут сделать ссылки на них. Это то, что вызывало вашу ошибку раньше, и именно поэтому мне нравится определять мою функцию -main внизу. Это вопрос стиля.

Другое дело, что ваша функция -main принимает переменные args прямо сейчас и не использует их. В clojure идиоматично использовать _ для обозначения параметра, который не используется. Вы можете использовать & _, чтобы избежать сообщений об ошибках, когда пользователь переходит в ненужные аргументы, но с самого начала я бы просто беззаботно выполнял функцию -main. Это связано с тем, что при запуске программы ничего не требуется, а ошибки облегчают отладку. Хорошо знать, что привыкает и где. Файл sample.csv уже предоставлен и имеет на нем read-file, поэтому программа должна запускаться, если ваша функция read-file верна, а файл sample.csv находится в правильном месте.

Что касается вашей функции -main, было бы неплохо провести там небольшой тест, чтобы убедиться, что она выполняется правильно при ее запуске, поэтому я изменил ее, чтобы распечатать содержимое файла csv на консоли. Этот способ печати из файла эффективен и стоит изучать самостоятельно.

Наконец, убедитесь, что вы включили clojure-csv.core в свой project.clj файл.

core.clj:

(ns fileops.core
  (:require
    [clojure-csv.core :refer [parse-csv]]))

(defn read-file
  "open and read the csv file"
  [fname]
  (with-open [file (clojure.java.io/reader fname)]
    (parse-csv (slurp fname)))) 

 (defn -main []
        (println (clojure.string/join "\n" (read-file "resources/test.csv"))))

project.clj:

...

:dependencies [[org.clojure/clojure "1.5.1"]
               [clojure-csv/clojure-csv "2.0.1"]
                ...]
:main fileops.core

Вам нужно объявить fileops.core как: main, как показано выше. Это говорит Leiningen, какую функцию выполнять при вводе lein run. Очень важные и хитрые вещи.

Итак, теперь убедитесь, что вы находитесь в корневой директории вашего проекта и на терминале, запустите следующее:

lein clean
lein deps 
lein run 

Удачи!

Дальнейшее чтение:

8-й светлый блог на пространствах имен

объяснение

Ответ 2

read-file должен быть перед main в вашем источнике, ИЛИ вы должны поместить перед -main причину объявления следующим образом:

(declare read-file)