Как реализовать лямбда-функцию как лямбда-функцию в Clojure? - PullRequest
16 голосов
/ 23 марта 2010

Я бы хотел иметь возможность определять лямбда-выражения, используя общий синтаксис Lisp, в Clojure. Например:

(lambda (myarg)
  (some-functions-that-refer-to myarg))

Это должно привести к так же, как:

#(some-functions-that-refer-to %)

В моем случае, я знаю, что у меня всегда будет ровно один аргумент, так что, возможно, это упростит вещи. (Но это можно назвать чем угодно - «myarg» или как угодно.)

Я подозреваю, что работоспособное решение - это "(defmacro lambda ...". Если это так, я не уверен, как лучше поступить. Как правильно перевести имя arg в%? правильная функция?

Или, есть ли более простое решение, чем написание моего собственного макроса, который на самом деле повторно реализует лямбда Clojure?

1 Ответ

26 голосов
/ 23 марта 2010

#(foo %) - просто сокращение от (fn [arg] (foo arg)).Нет причин писать макрос, который расширяется до #(...).Все % в конструкции #(...) в любом случае сразу развертываются в gensyms.

user> `#(foo % %1 %2)
(fn* [user/p1__1877 user/p2__1878] 
  (user/foo user/p1__1877 user/p1__1877 user/p2__1878))

Если вы когда-либо пишете макрос, который расширяется для создания анонимных функций, вы можете просторазверните их до fn форм самостоятельно.В вашем случае вам, вероятно, следует просто использовать fn напрямую и пропустить макросы.fn - это Clojure lambda.

Разница между (fn [] ...) и (lambda () ...) в этом случае заключается в том, что «fn» короче типа, чем «лямбда», а fn принимает вектор дляего привязки, тогда как lambda занимает список.Если вы используете Clojure, вам в конечном итоге придется к этому привыкнуть, поскольку векторы всегда используются для наборов привязок во всех формах do, а также в for и binding и т. Д.Я понимаю, что списки используются для вызовов функций или макросов, а векторы используются для вещей, которые не являются вызовами (списки символов для привязки, например).Возможно, это облегчает визуальное сканирование кода, а не списки.Clojure - это не Common Lisp, и вы будете испытывать боль, если попытаетесь заставить его быть.

Если вы действительно, действительно хотели это сделать, просто сказать, что вы это сделали:

user> (defmacro lambda [args & body]
        `(fn ~(vec args) ~@body))
user> ((lambda (x) (println x)) "foo")
foo
nil

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

...