Clojure выдает ошибку только при использовании пространства имен

#clojure #leiningen #clojure-contrib

#clojure #leiningen #clojure-contrib

Вопрос:

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

 (ns chess.core
    (:require clojure.contrib.str-utils2))
  

а также определяет несколько функций, в том числе to-string , которая превращает символ для игровой фигуры в строку. Однако, когда я компилирую:

 core.clj:21:8:
  error: java.lang.Exception: Unable to resolve symbol: to-string in this context (core.clj:21)
  

Я провел некоторые эксперименты и обнаружил, что получаю ошибку при первом вызове функции, которую я определил сам. Я также обнаружил, что обычно я не получаю ошибку, если закомментирую ns вызов. Иногда это можно исправить, перезапустив сервер Swank (а иногда и нет). Какое-то время у меня просто был (ns chess.core) , который выдавал ту же ошибку, поэтому я прокомментировал это и продолжил взлом. Но теперь мне нужно что-то прописное, поэтому мне нужны str-utils.

Говоря о str-utils, я использую Leiningen, и у меня есть следующее в project.clj разделе :dependencies :

                  [org.clojars.jhowarth/clojure-contrib "1.2.0-RC3"]]
;                [clojure.contrib.str-utils2 "1.2.1"]]
  

Верхний работает, нижний — нет.

Итак, я чувствую, что я просто неосведомлен о том, как работают пространство имен и библиотеки Clojure, но в то же время все остальные, похоже, успешно используют (ns foo.bar) .

Ответ №1:

При компиляции определения оцениваются сверху вниз. Если вы обратитесь к функции, которая определена позже в файле, вы получите эту ошибку. Я думаю, что, удаляя ns вверху, вы фактически ссылаетесь на функцию с тем же именем в другом пространстве имен (вероятно, пользовательское ns по умолчанию).

Если вы не можете переместить функцию выше ее первого использования, вы можете сделать (declare to-string) вверху и определить ее позже.

Что касается пакета str-utils2, он уже должен быть в clojure-contrib 1.2X. Начиная с версии 1.3 (которая еще не завершена), содержимое будет разделено. Смотрите http://groups.google.com/group/clojure/msg/c5cdfec990efb6f4

Комментарии:

1. Спасибо! Теперь я знаю, что у Clojure есть однопроходный компилятор. Я немного удивлен, что это не отображается более заметно на веб-сайте… как здесь . И об этом полезно знать (declare) , но я предполагаю, что мне следует немного больше подумать о том, как я разделяю свой проект на несколько файлов.

2. Большинство lisps выполняют компиляцию только за один проход, поскольку очень часто (повторно) компилируют и загружают отдельные инструкции во время разработки вместо целых файлов. Clojure также ожидает, что все свободные переменные будут определены при компиляции, откуда и возникает ошибка, но я подозреваю, что это в основном из соображений производительности / взаимодействия, поскольку Common Lisp, например, не применяет это.

3. Вот что Рич Хикки говорит по этому поводу. Это преднамеренное дизайнерское решение.

Ответ №2:

Трудно сказать, не видя, как вы используете to-string функцию, но вы могли бы ознакомиться с этим объяснением того, как require , ns и use работают: http://blog.8thlight.com/articles/2010/12/6/clojure-libs-and-namespaces-require-use-import-and-ns . В нем отражены вещи, которые лично меня смущали в отношении библиотек и пространств имен.

Комментарии:

1. Это именно та статья, которую я хотел бы найти. Спасибо за ссылку.