2015-07-27 7 views
9

Рассмотрим следующий макрос:разница между пусть и пусть * в Clojure

(defmacro somemacro [] 
    (list 'let ['somevar "Value"] 'somevar)) 

Расширяя это дает следующий результат:

(macroexpand '(somemacro)) 

Результат:

(let* [somevar "Value"] somevar) 

У меня есть два вопроса около let * (со звездой):

  • Что это значит? (В частности: где-то это документировано?)
  • Почему макрос не расширен с помощью «нормального» let? (I.e., пусть без звездочки.) Оба дают тот же результат (в моих экспериментах). Есть ли встречный пример?

К сожалению, я не могу найти официальную документацию о let *, поэтому я прошу здесь.

Источники я уже рассматривал:

(doc let*) ; --> nil 
(source let*) ; --> source not found 
  1. https://clojuredocs.org/clojure.core -> я не знаю, пусть * здесь (хотя есть, например, список *)
  2. https://clojuredocs.org/clojure.core/let -> упоминается только один раз в комментарий, который не совсем ясен для меня:

    Nota Bene: let Clojure - это как пусть * в схеме - каждый init-expr имеет доступ к th предшествующие формы связывания. (Существует также пусть *, но это более или менее пусть без деструктуризации, а на самом деле является основной реализацией.)

  3. LET versus LET* in Common Lisp -> этот вопрос о Common Lisp, но, возможно, это то же самое в Clojure?
  4. Ответ: https://stackoverflow.com/a/5084339/3398271

    В Clojure это в основном означает "Foo *, как Foo, но почему-то разные, и вы, вероятно, хотите Foo". Другими словами, это означает, что автор этого кода не смог найти лучшего имени для второй функции, поэтому они просто набросали на него звезду.

-> Является ли это в случае пусть и пусть *? Но если это так, остается вопрос, какая разница?

  1. What is the difference between let and let* in Scheme? -> Это то же самое в Clojure?
+0

Существует, по-видимому, пара 'if' и' if * '. Как и с 'let', документация найти нелегко. Я не знаю, что «если» разрушает, поэтому что-то еще должно продолжаться. –

+0

@ Reb.Cabin, Интересно. Если 'if *' не документируется, он, вероятно, является внутренним и не предназначен для потребления. Я посмотрел источник Clojure на GitHub, но поиск GitHub разделил «*». Есть много случаев 'if'. Я полагаю, что ответ заключается в том, чтобы загрузить источник локально и запустить 'grep' локально. –

ответ

11

let* - внутренняя деталь реализации. let - макрос, реализованный в терминах let*. https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L4301

Макрос let добавляет параметр destructuring к let*.Это стандартная модель для xyz и xyz* в Clojure, с версией *, не документированной. Исключение составляют list и list*.

+0

Спасибо за объяснение, я попробовал это, и на самом деле '(пусть [[abc & d: as e] [1 2 3 4 5 6 7]] [abcde])' работает, пока '(пусть * [[ abc & d: as e] [1 2 3 4 5 6 7]] [abcde]) вызывает исключение CompilerException. – Attilio

+1

Возможно, я не был чист. 'let *' не имеет деструктурирования. Макрос 'let' вызывает' let * ', обеспечивая деструктурирование в процессе. –

+0

Да, я полностью это понял (я имел в виду, это то, что я нашел пример, который доказывает именно это :)) Извините за путаницу. – Attilio

0

Я думал, я хотел бы добавить, что причина, почему macroexpand возвращается let* вместо let можно найти в documentation of macroexpand:

Многократно называет MACROEXPAND-1 по форме, пока она больше не не представляет макросъемки формы, то возвращает его.

Так что же происходит это первый вызов macroexpand-1(let [somevar "Value"] somevar) возвращается, а второй расширяется let в let*.

Действительно,

user=> (println (clojure.string/join "\n" (take 3 (iterate macroexpand-1 '(somemacro))))) 
(somemacro) 
(let [somevar "Value"] somevar) 
(let* [somevar "Value"] somevar) 
nil 

Если вы должны были использовать деструктурирующий в макросе, то результат будет более интересным:

user=> (defmacro destructuring-macro [] `(let [[x y z] [:x :y :z]] y)) 
#'user/destructuring-macro 

user=> (println (clojure.string/join "\n" (take 3 (iterate macroexpand-1 '(destructuring-macro))))) 
(destructuring-macro) 
(clojure.core/let [[testing.core/x testing.core/y testing.core/z] [:x :y :z]] testing.core/y) 
(let* [vec__8356 [:x :y :z] x (clojure.core/nth vec__8356 0 nil) y (clojure.core/nth vec__8356 1 nil) z (clojure.core/nth vec__8356 2 nil)] testing.core/y) 
nil 

Обратите внимание, что let полностью квалифицированное синтаксисом цитаты, потому что он не является особой формой (хотя в ее документации это сказано). Основная специальная форма - let*, которая не полностью соответствует цитате синтаксиса.