Как определить функцию внутри функции в Clojure и ссылаться на эту функцию? - PullRequest
15 голосов
/ 04 ноября 2011

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

(fn [x y] (set (concat 
  (keep-indexed #(if (nil? (get y %2)) %2) x)
  (keep-indexed #(if (nil? (get x %2)) %2) y))))

Очевидно, я бы предпочел что-то вроде:

(fn [x y] (set (concat (diff x y) (diff y x))))

Где функция diff определена и ссылается на "inline", но я не знаю, как это сделать в одном блоке fn.

Ответы [ 2 ]

23 голосов
/ 04 ноября 2011

Используйте let или letfn:

(fn [x y]
  (let [diff (... function body here ...)]
   (set
    (concat (diff x y) (diff y x)))))
11 голосов
/ 04 ноября 2011

Одна из особенностей, которая делает Clojure шуткой (и функциональным языком в целом), заключается в том, что функции - это вещи первого класса в Clojure, в частности, они являются объектами.Когда вы создаете функцию с помощью (defn name [arg] ...) if, создаете функцию и затем сохраняете ее в var, чтобы вы могли найти ее позже в любом месте вашей программы.это примерно так:

(def name (fn [arg] ...))

теперь имя содержит функцию, которая широко доступна.Функции не должны храниться в VARS, особенно если они нужны только внутри вашей функции.В этом случае имеет смысл связать функцию с локальным именем, как в ответе Мэтта Фенвика.

(let [name (fn [agr] ...)] ...)

макрос letfn делает это более элегантным.Важно понимать, что функции - это объекты, которые хранятся в вещах, и вы можете выбрать контейнер, который соответствует вашим потребностям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...