在本地环境中定义和访问变量

时间:2019-06-26 10:41:11

标签: scope macros common-lisp

在学习了CL并在不同的小项目中作为爱好练习了一段时间之后,我的个人CL图上仍然有一些空白区域。最近,我有许多函数都使用相同的owner构造,并且我想到编写一个宏来使代码更简洁:

// Loop through the items
foreach( $array as $item ):
    echo $item;
endforeach;

以便以后可以定义类似的功能(仅作为最小示例):

// Change final item
echo $item . 'last item';

现在,我想知道是否可以使用let之类的宏/函数来缩短(defmacro with-context (&body body) `(let ((context (make-array 4 :element-type 'fixnum :initial-contents '(0 1 2 3)))) ,@body)) 表达式。

(defun test-a ()
  (with-context
    (setf (aref context 3)
          (+ (aref context 0) (aref context 1)))
    context))

但是变量(aref context n)当然在编译时是未知的。我只是不知道我是否在这里有一些基本的误解,或者我怎么能告诉lisp我真正想要的是什么。所以,我的问题基本上是,是否有可能,这是否是个好主意。

2 个答案:

答案 0 :(得分:4)

本地函数怎么了?

(defmacro with-context (&body body)
  `(let ((context (make-array 4 :initial-contents '(0 1 2 3))))
     (flet ((context (n)
              (aref context n)))
       ,@body)))

也进行设置:

(defmacro with-context (&body body)
  `(let ((context (make-array 4 :initial-contents '(0 1 2 3))))
     (flet ((context (n)
              (aref context n))
            ((setf context) (new n)
              (setf (aref context n) new)))
       ,@body)))

答案 1 :(得分:3)

您可以在宏扩展中放入 Private Sub Form_formclosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) Handles MyBase.FormClosing If inEditMode Then Dim dialog As DialogResult = MessageBox.Show("You can't exit the program when in edit mode. Please save your changes before exiting the program.") If DialogResult = DialogResult.OK Then e.Cancel = True End If Else Dim dialog As DialogResult = MessageBox.Show("Do you really want to close the program? Any unsaved changes will be lost.", "Exit Application?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) If dialog = DialogResult.Yes Then Application.ExitThread() ElseIf dialog = DialogResult.No Then e.Cancel = True End If End If End Sub '^warns user before closing the application^

macrolet

一些个人笔记:

我不喜欢照应宏,因此通常让用户为上下文定义名称。不过,对于(defmacro with-context (&body body) (with-gensyms (i) `(let ((context (make-array 4 …))) (macrolet ((context (,i) `(aref context ,,i))) ,@body)))) 宏,这会感到奇怪。然后,我可能得出的结论是,我想要的只是一个context函数,并继续使用make-standard-context。我认为这与一般指南“常规”保持一致。