Owe*_*n_R 0 variables scope global-variables common-lisp local-variables
let
(defun demo1 ()
(let ((a 1)
(b 2))
; these print fine
(print a)
(print b)))
(demo1)
; these get "no value" errors, as expected
(print a)
(print b)
Run Code Online (Sandbox Code Playgroud)
输出:
1
2 *** - EVAL: variable A has no value
Run Code Online (Sandbox Code Playgroud)
let
,变量逃脱(对于习惯于更现代的范围规则的人来说,这是非常令人惊讶的,例如ruby's)
(defun demo2 ()
(setf a 1)
(setf b 2)
; these print fine
(print a)
(print b))
(demo2)
; these escape, and also print with no error!
(print a)
(print b)
Run Code Online (Sandbox Code Playgroud)
输出:
1
2
1
2
Run Code Online (Sandbox Code Playgroud)
你怎么可以让他们无法逃脱呢?
我monkey'd周围setq
和defvar
(这是在唯一的结果,我可以通过查找文档上的"局部变量"找到提到)
,但没有喜悦可言
(
这是我想要首先解决的实际问题 - 强制你使用额外的parens层
的语法let
,
并将整个函数体包裹在最外层,
这使得它更难以读取和写入没有理由
(因为绝大多数最常见的用例let
总是包含整个函数体而没有别的),
所以我想制作一个with
宏而不是
)
(defmacro with (&rest list-of-pairs)
(loop for (name value) in list-of-pairs
do `(setf ,name ,value) ;A
; do (setf name value) ;B
; (i tried both A and B)
))
(defun demo3 ()
(with (a 1)
(b 2))
; this gets a "no value" error when called
(print a)
(print b))
(demo3)
; it never even gets to this point cuz of the above error
(print a)
(print b)
Run Code Online (Sandbox Code Playgroud)
输出:
*** - PROGN: variable A has no value
Run Code Online (Sandbox Code Playgroud)
如何让变量转移到函数范围而不是超出?
[
这个问题问道
任何人都可以告诉我如何在lisp中定义局部变量而不是let?
但没有一个答案对我有帮助
]
思考方式的loop
宏观作品
(但从人的角度呼唤它不理解它的内部,我的意思)......
好了,请看:
(loop for i from 1 to 5
do (print i))
Run Code Online (Sandbox Code Playgroud)
我还不知道loop
看起来是什么样的定义,
但它是抽象的类似的东西,对吧?:
(defmacro loop ([args somehow,
including the `sexpr`
which goes after the `do` keyword in the macro call])
[other stuff]
do ([sexpr])
[other stuff])
Run Code Online (Sandbox Code Playgroud)
(我只关注do
关键字作为一个例子,因为调用的语法相对简单.)
所以我真正需要做的是制作我自己的my-defun
宏
并包含一个with
关键字,
对吗?
这样的事情:
(defmacro my-defun ([args somehow,
including a `paired-list-of-names-and-values`
to go after a `with` keyword in the macro call])
(let
([paired-list-of-names-and-values])
([function body])))
(my-defun demo4 ()
with (
(a 1)
(b 2)
)
; this should print
(print a)
(print b))
(demo4)
; this should get a "no value" error
(print a)
(print b)
Run Code Online (Sandbox Code Playgroud)
我在这里走在正确的轨道上吗?
如果是的话,我从哪里开始?
比如,什么是一些简单,直接的宏定义,我可以看看它们是如何工作的?
或类似的东西
简单的规则:SETF
或者SETQ
不创建变量.无论是本地还是全球.他们只是设置变量.
永远不要使用SETQ
和设置未定义的变量SETF
.这是Common Lisp,不是Ruby
.
SETF
使用宏创建表单也没有用.为什么这会有所作为?
定义局部变量
如果你看看Common Lisp的标准,还有数不胜数的结构允许定义局部变量:DEFUN
,DEFMETHOD
,LET
,LET*
,DO
,DOTIMES
,FLET
,LABELS
,LAMBDA
,DESTRUCTURING-BIND
,MULTIPLE-VALUE-BIND
,...
函数中的局部变量
如果查看函数,函数的参数列表允许您定义局部变量:
您可以定义功能LAMBDA
,DEFUN
...
示例&optional
:
((lambda (a &optional (b 20))
... ; a and b are known here inside the function
)
10) ; we don't need to pass an arg for `b`, optional!
Run Code Online (Sandbox Code Playgroud)
示例&aux
:
((lambda (a &aux (b (+ a 20)))
... ; a and b are known here inside the function
)
10) ; we CAN't pass an arg for `b`, auxiliary!
Run Code Online (Sandbox Code Playgroud)
LOOP中的变量
你不需要猜测LOOP宏的作用,你可以让Lisp向你展示 - 这里使用LispWorks:
CL-USER 27 > (pprint (macroexpand '(loop for i from 1 to 5
do (print i))))
(BLOCK NIL
(MACROLET ((LOOP-FINISH () '(GO #:|end-loop-82961|)))
(LET ((I 1)
(#:|to-82964| 5)
(#:|by-82965| 1))
(TAGBODY (PROGN (SYSTEM::INTERNAL-IF (OR (> I #:|to-82964|))
(GO #:|end-loop-82961|)))
#:|begin-loop-82960|
NIL
(PRINT I)
(PROGN
(LET ((#:|temp-82966| (+ I #:|by-82965|)))
(SETQ I #:|temp-82966|))
(SYSTEM::INTERNAL-IF (OR (> I #:|to-82964|))
(GO #:|end-loop-82961|)))
(GO #:|begin-loop-82960|)
#:|end-loop-82961|
(RETURN-FROM NIL NIL)))))
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它扩展为一个表单,其中变量i
由a引入LET
.它还扩展为一个使用goto构造的形式.
如您所见,您可以在Lisp中实现一种非常精美的语法 - 如LOOP语法.但是LOOP的实现很大而且非平凡.对于初学者来说没什么.