#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. Это именно та статья, которую я хотел бы найти. Спасибо за ссылку.