Поиск…


Когда нужно группировать?

В некоторых местах в Common Lisp ряд форм оценивается по порядку. Например, в теле defun или лямбда , или в теле доты . В этих случаях запись нескольких форм в порядке работает, как ожидалось. Однако в нескольких местах, таких как части then и else выражения if , допускается только одна форма. Конечно, можно захотеть на самом деле оценить несколько выражений в этих местах. Для этих ситуаций требуется какая-то неявная явная форма группировки.

Progn

Общего назначения специальный оператор progn используется для оценки ноль или более форм. Возвращается значение последней формы. Например, в следующем случае (print 'hello) оценивается (и его результат игнорируется), а затем 42 оценивается и возвращается его результат ( 42 ):

(progn 
  (print 'hello)
  42)
;=> 42

Если в запросе нет форм, то возвращается nil :

(progn)
;=> NIL

Помимо группировки ряда форм, progn также имеет важное свойство, что если форма progn является формой верхнего уровня , то все формы внутри нее обрабатываются как формы верхнего уровня. Это может быть важно при написании макросов, которые расширяются в несколько форм, которые все должны обрабатываться как формы верхнего уровня.

Progn также ценен тем, что он возвращает все значения последней формы. Например,

(progn
  (print 'hello)
  (values 1 2 3))
;;=> 1, 2, 3

Напротив, некоторые выражения группировки возвращают первичное значение формы, создающей результат.

Неявные Прогнозы

Некоторые формы используют неявные прогнозы для описания их поведения. Например, когда и если макросы, которые по существу являются односторонними , если формы, описать их поведение с точки зрения неявного progn. Это означает, что такая форма, как

(when (foo-p foo)
  form1
  form2)

и условие (foo-p foo) истинно, тогда форма 1 и форма 2 сгруппированы так, как если бы они содержались в прогнозе . Расширение когда это макрос, по существу:

(if (foo-p foo)
  (progn
    form1
    form2)
  nil)

Prog1 и Prog2

Часто бывает полезно оценить несколько выражений и вернуть результат из первой или второй формы, а не из последней. Это легко сделать, используя let и, например:

(let ((form1-result form1))
  form2
  form3
  ;; ...
  form-n-1
  form-n
  form1-result)

Поскольку эта форма распространена в некоторых приложениях, Common Lisp включает prog1 и prog2 , которые похожи на progn , но возвращают результат первой и второй форм, соответственно. Например:

(prog1
  42
  (print 'hello)
  (print 'goodbye))
;; => 42
(prog2
  (print 'hello)
  42
  (print 'goodbye))
;; => 42

Однако важное различие между prog1 / prog2 и progn заключается в том, что progn возвращает все значения последней формы, тогда как prog1 и prog2 возвращают первичное значение первой и второй форм. Например:

(progn
  (print 'hello)
  (values 1 2 3))
;;=> 1, 2, 3

(prog1
  (values 1 2 3)
  (print 'hello))
;;=> 1              ; not 1, 2, 3

Для нескольких значений с оценкой стиля prog1 вместо этого используйте multiple-value-prog1 . Нет аналогичного многозначного prog2 , но его нетрудно реализовать, если вам это нужно.

блок

Специальный блок оператора позволяет группировать несколько форм Лиспа (например, неявное progn ), а также имя, чтобы назвать этот блок. Когда формы внутри блока оцениваются, для выхода из блока можно использовать специальный оператор return-from . Например:

(block foo
  (print 'hello)     ; evaluated
  (return-from foo)
  (print 'goodbye))  ; not evaluated
;;=> NIL

return-from также может быть предоставлено возвращаемое значение:

(block foo
  (print 'hello)     ; evaluated
  (return-from foo 42)
  (print 'goodbye))  ; not evaluated
;;=> 42

Именованные блоки полезны, когда кусок кода имеет значимое имя или когда блоки вложены. В каком-то контексте важна только возможность возврата из блока раньше. В этом случае вы можете использовать nil в качестве имени блока и вернуться . Возврат точно так же, как return-from , за исключением того, что имя блока всегда равно нулю .

Примечание: закрытые формы не являются формами верхнего уровня. Это отличается от progn , где вложенные формы с верхним уровнем progn формы по - прежнему считаются формами верхнего уровня.

Tagbody

Для большого контроля в групповых формах специальный оператор tagbody может быть очень полезным. Формы внутри формы тегов - это либо теги go (которые являются просто символами или целыми числами), либо формы для выполнения. Внутри тега используется специальный оператор go для передачи выполнения в новое место. Этот тип программирования можно считать довольно низким, так как он допускает произвольные пути выполнения. Ниже приведен подробный пример того, как может выглядеть цикл for при реализации в качестве тега :

(let (x)               ; for (x = 0; x < 5; x++) { print(hello); }
  (tagbody
     (setq x 0)
   prologue
     (unless (< x 5)
       (go end))
   begin
     (print (list 'hello x))
   epilogue
     (incf x)
     (go prologue)
   end))

Хотя tagbody и go обычно не используются, возможно, из-за «GOTO считается вредным», но могут быть полезны при реализации сложных структур управления, таких как государственные машины. Многие итерационные конструкции также расширяются в неявный тег . Например, тело топимов указано как серия тегов и форм.

Какую форму использовать?

При написании макросов, которые расширяются в формы, которые могут включать группировку, стоит потратить некоторое время на рассмотрение того, какая структура группировки будет расширяться.

Для форм стиля определения, например, макроса define-widget , который обычно отображается как форма верхнего уровня, и что несколько defun s, defstruct s и т. Д., Обычно имеет смысл использовать progn , так что дочерние формы обрабатываются как формы верхнего уровня. Для итерационных форм чаще всего используется неявный тег .

Например, тело DOTIMES , DOLIST , и сделать каждый расшириться в неявном tagbody.

Для форм, которые определяют именованный «кусок» кода, часто используется неявный блок . Например, в то время как тело defun находится внутри неявного прогноза , этот неявный progn находится внутри блока, совместно использующего имя функции. Это означает, что return-from может использоваться для выхода из функции. Такой комп



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow