Возможно ли определение безымянных макросов?(Макросы "лямбда"?) - PullRequest
0 голосов
/ 11 октября 2018

Моя цель - оценить выражение во время компиляции, как некоторые простые вещи, как (+ 1 1).Но я хотел бы, чтобы целое число «2» компилировалось вместо полной операции «1 + 1», выполняемой во время выполнения, без использования именованного макроса .Это делает мой исходный код более понятным, показывая, как я получил значение «2», не тратя при этом процессорное время, повторяя ту же операцию «1 + 1».Вот простой пример, иллюстрирующий основную идею, но не для реальных случаев, скажем, моя идеальная цель функция defun выглядит следующим образом:

(defun test ()
   (+ 1 2 3))

Мне бы хотелось, чтобы буквально «2» было вычисляется во время компиляции , поэтому я использую eval-when-compile :

(defun test ()
   (+ 1 
      (eval-when-compile (+ 1 1)) 
      3))

Однако получается:

(defun test ()
   (+ 1 '2 3))

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

Определение именованного макроса works:

(defmacro 1+1 () `,(+ 1 1))
(defun test ()
   (+ 1 (1+1) 3))

Это даст мой идеальный результат без quote с добавлением целого числа "2":

(defun test ()
    (+ 1 2 3))

Есть ли простой способ, подобный приведенному выше eval-when-compile для достижения этого в defun ?Что-то вроде безымянного макроса, чтобы избавиться от именованного помощника 1 + 1 , или я должен назвать это "лямбда-макрос" ?

Ответы [ 3 ]

0 голосов
/ 12 октября 2018

Я не знаю способа создания анонимных макросов, но macrolet облегчает временную область для именованных макросов, которую вы можете использовать следующим образом:

(defun foo ()
  (macrolet ((docstring () (concat "foo" "bar")))
    (docstring))
  'foo)

Обратите внимание, что если это действительно только для строк документации, вы можете вместо этого сделать это:

(defun foo () 'foo)
(put 'foo 'function-documentation (concat "foo" "bar"))
0 голосов
/ 12 октября 2018

Вдохновленный ответом @phils, я наконец смог определить анонимные макросы и запустить их.Я определяю вспомогательный макрос с именем немедленный , чтобы помочь решить эту проблему;он в основном определяет функцию анонимного макроса временно, используя macrolet , затем запускает ее:

(defmacro immediate (body)
  "Define an anonymous macro and run it immediately"
  (let ((f (make-symbol "immed")))
    `(macrolet ((,f () ,body))
       (,f))))

С немедленным , я могу переписать пример кода в моем исходном вопросе этопуть:

(defun test ()
  (immediate (concat "Docstring" " of " "test" ))
  (+ 1
     (immediate (+ 1 1))
     3))

Функция test будет определена точно так, как я ожидал:

(defun test ()
  "Docstring of test"
  (+ 1 2 3))

(Имя немедленное вдохновлен непосредственными словами из Forth языка.)

0 голосов
/ 11 октября 2018

Вы думаете о постоянном сворачивании.Это не требуется, но это делают самые быстрые компиляторы.Вот пример из SBCL:

* (defun test () (+ 1 2 3))

TEST
* (disassemble #'test)

; disassembly for TEST
; Size: 22 bytes. Origin: #x100189010C
; 0C:       498B4D60         MOV RCX, [R13+96]                ; no-arg-parsing entry point
                                                              ; thread.binding-stack-pointer
; 10:       48894DF8         MOV [RBP-8], RCX
; 14:       BA0C000000       MOV EDX, 12
; 19:       488BE5           MOV RSP, RBP
; 1C:       F8               CLC
; 1D:       5D               POP RBP
; 1E:       C3               RET
; 1F:       0F0B0F           BREAK 15                         ; Invalid argument count trap
NIL

Вы не видите никаких добавлений, но видите константу 12, которая является адресом указателя для fixnum 6

Здесь, в CLISP:

[2]> (disassemble #'test)

Disassembly of function test
(CONST 0) = 6
0 required arguments
0 optional arguments
No rest parameter
No keyword parameters
2 byte-code instructions:
0     (const 0)                           ; 6
1     (skip&ret 1)
nil

Таким образом, если вы используете современную реализацию Common Lisp, которая не является комедией, вам не нужно думать об этих вопросах.

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