2014-12-17 3 views
2

Я провел пару лет, выполняя Схему «в тот же день», и теперь изучаю Clojure. Одной из «лучших практик» в Схеме было определение вспомогательных функций внутри родительской функции, что ограничивало их видимость «снаружи». Конечно, тогда TDD не было сделано (или не было!), Поэтому тестирование таких функций не было проблемой.Единичное тестирование локальных функций (letfn) в Clojure?

Я все еще испытываю соблазн структурировать функции Clojure таким образом; то есть, используя letfn для связывания вспомогательных функций в основной функции. Конечно, тестирование таких «локальных» функций проблематично. Я понимаю, что могу определить «частные» функции, но это позволяет видеть видимость в пространстве имен, которое помогает, но не так тонко. Если вы сталкиваетесь с letfn в рамках другой функции, довольно ясно, что эта функция недоступна для общего использования.

Итак, на мой вопрос, можно ли проверить такие локальные функции, и если да, то как? Если нет, то есть ли какое-то соглашение, помогающее в чтении кода, так что ясно, что функция имеет только один вызывающий?

ТИА, Билл

+3

Почему модуль тестирует внутреннюю логику функции? Если он настолько сложный, что части должны тестироваться отдельно, есть преимущество в том, чтобы устанавливать определения в их собственных формах верхнего уровня. – noisesmith

+0

Хм. Помимо видимости, есть проблема, что letfn может закрыть символ, «переплетая» его. –

+0

Предоставляет ли система состояния Lisp возможность справиться с этой проблемой? Если да, то есть ли эквивалент Clojure? – Thumbnail

ответ

0

Обычный подход просто положить функции в пространстве имен.

Одним из вариантов является использование метаданных:

user=> (defn ^{::square #(* % %)} cube [x] 
    #_=> (* x ((::square (meta #'cube)) x))) 
#'user/cube 
user=> (meta #'cube) 
{…, :user/square #<user$fn__780 [email protected]>} 
user=> (cube 3) 
27 

Это, конечно, можно написать макрос, чтобы сделать это похорошела.

+4

Я до сих пор не видел этот подход к метаданным, и это заставляет меня хотеть бросить. Я не вижу в этом никакого преимущества; это просто грубый способ сделать: частную функцию. Если вы хотите что-то более личное, чем: private, используйте letfn; метаданные не являются разумным компромиссом. – amalloy

+0

@amalloy OP не хочет, чтобы он был закрыт как 'letfn'. OP хочет иметь доступ к функции из любой области. – rightfold

+1

Итак, сделайте функцию общедоступной, с запиской на ней, в которой говорится: «Не используйте это, если у вас нет веской причины». Или сделайте его приватным и прорвется через него. – amalloy

Смежные вопросы