lisp中的变量

本文探讨Lisp中的变量类型,包括词法变量(类似局部变量)和动态变量(类似全局变量)。Lisp的变量无需预先声明类型,它们是对象的引用。通过函数形参、Let和Let*特殊操作符来引入新变量,Let*允许内部变量引用外部变量。全局变量由DEFVAR和DEFPARAMETER定义,动态变量的绑定存在于栈中,每次设置都会影响最近的绑定。文章还介绍了incf、decf、rotatef和shiftf等修改宏。

支持两种类型变量:词法变量(lexical)和动态变量(dynamic),分别对应于其他语言中的局部变量和全局变量,只能说是大致相似,并不是所有的语言都有lisp中的闭包的词法作用域变量

与其他语言一样,Common Lisp中的变量时一些可以保存值的具体位置,但他不像java,C++等语言那样带有确定的类型,也就是说不用声明对象所保存的对象的类型。

Common lisp中所有的值都是对象的引用,将一个变量赋予心智就会改变该变量所指向的对象。

1:引入新变量的方式:

       1:定义函数形参。形参列表定义了当函数被调用时用来保存实参的变量,也就是用来指向特定对象。绑定代表了变量在运行期的存在。

       2Let特殊操作符。

            (let (variable*) body-form*)

 平时如果你直接( setf i 4)他总会提示说undefined variable,这是如果你在前面引入let就行了。

如果嵌套引入了同名变量的绑定形式,最内层的变量绑定将覆盖外层的绑定,

用于体现当传给x值时是进行栈式的,刚开始x指向1,然后2进栈,他就指向了2,一旦出词法作用域,最上面的就会出栈,从而暴漏上一个绑定。

CL-USER> (defun foo(x)
	   (format t "Parameter:~a~%" x)
	   (let ((x 2))
	     (format t "outer let:~a~%" x)
	     (let ((x 3))
	       (format t "inner let:~a~%" x))
	     (format t "outer let:~a~%" x))
	   (format t "Parameter:~a~%" x))
FOO
CL-USER> (foo 1)
Parameter:1
outer let:2
inner let:3
outer let:2
Parameter:1
NIL

CL-USER> (let ((x 10))
	   (let ((x (+ x 10)))
	     (list x)))
(20)
CL-USER> (let ((x 10))
	   		(let ((x (+ x 10)))
	     		(list x))
	   	   (list x))
(10)

LetLet*的区别:(let (variable *) body-form*) 

Let 中被绑定的变量名只能用在let的形式体中,即body-form

Let* 每个变量的初始形式,都可以引入列表中比他先引入的变量。Variable中的变量y可以用他前面的x来定义

CL-USER> (let* ((x 10)
            (y (+ x 10)))
            (list x y))	
(10 20)CL-USER> (let ((x 10)
            (y (+ x 10)))
            (list x y))


2:闭包的词法作用域见 lambda 注意点中4.点击打开链接

3:动态变量

Common lisp 提供两种创建全局变量的方式DEFVAR/DEFPARAMETER

CL-USER> (defvar *count* 0)
*COUNT*
CL-USER> (defparameter *ap-tolerance* 0.1)
*AP-TOLERANCE*

两种区别:DEFPARAMETER总是将初始值赋给命名的变量,而DEFVAR只有当变量未定义时才这么做,DEFVAR也可以不带初始值使用,这时为未绑定。

从实践上来说DEFVAR定义某些变量,这些变量所含数据是持久存在的。

DEFVAR 可以使用setf来设定,或者用MAKUNBOUND先将其未绑定,再重新求值DEFVAR形式。

多数语言将标准输入与输出流保存在全局变量里面,*standard-output*

所有的全局变量事实都是动态变量。Let只会临时改变其绑定,而setf会直接改变所指位置的值。

一个动态变量的每个新绑定都将被推到一个用于该变量的绑定栈中,而对该变量的引用总是使用最近的绑定,当绑定形式返回时,他们所创建的绑定会从栈上弹出,从而暴露前一个绑定。(这句话正好总结了前面let 中输出1 2 3 2 1 的原因),从下面的例子你也就看出为啥全局变量都是动态变量啦。

CL-USER> (defvar *x* 10)
*X*
CL-USER> (defun foo()(format t "x: ~d~%" *x*))
	   
STYLE-WARNING: redefining COMMON-LISP-USER::FOO in DEFUN
FOO
CL-USER> (defun bar () 
	   (foo)
	   (let ((*x* 20)) (foo))
	   (foo))
BAR
CL-USER> (bar)
x: 10
x: 20
x: 10
NIL
CL-USER> (defun foo()
	   (format t "before assginment ~18tx: ~d~%" *x*)
	   (setf *x* (+ 1 *x*))
	   (format t "after assginment ~18tx: ~d~%" *x*))
FOO
CL-USER> (bar)
before assginment  x: 10
after assginment  x: 11
before assginment  x: 20
after assginment  x: 21
before assginment  x: 11
after assginment  x: 12
4:赋值

Simple variable :      (setf x 10)

Array:                    (setf (aref a 0) 10)   

Hash table:            (setf (gethash 'key hash) 10)

Slot named 'field':   (setf (field o) 10)

(incf x )      ==(setf x (+ x 1))

(decf x )     ==(setf x (- x 1))

(incf x 10)   == (setf x (+ x 10)

incf decf都是修改宏,类似的还有如下俩个

rotatef 返回nil, shiftf 返回第一个参数最初的值

(rotatef a b c) 也就是互相交换值,c->b->a->c  

(shiftf a b c 10) 10->c->b->a  它们两个都是从右往前赋值,但是rotatef正如单词它是轮,所以是一个连接起来的话,因为值相当于往前挪了一位,

CL-USER> (let ((a  1)(b 2)(c 3))
   (format t "~s ~s ~s~%" a b c)
   (format t "~s~%" (rotatef a b c))
   (format t "~s ~s ~s~%" a b c)
   (format t "~s~%" (shiftf a b c 10))
   (format t "~s ~s ~s~%" a b c)
   (format t "~s~%" (shiftf a b c ))
   (format t "~s ~s ~s~%" a b c))
1 2 3
NIL
2 3 1
2
3 1 10
3
1 10 10
NIL


下面是C++语言中值传递跟引用传递的例子

int swap(int a, int b) //交换a,b的值
{
int temp = a;
a = b;
b = a;
}


void main()
{
int m = 10, n =20;
swap(m,n);
cout<<m<<endl;
cout<<n<<endl;
//这里m还是10,n还是20,因为传给swap的其实是m,n的拷贝,swap改变的是m和n的拷贝的值,并没有改变m,n的值,因为swap的参数是按值传递的。也就是说在swap中,其实创建了两个临时变量,一个的值为m的值10,另一个的值是n的值20,然后交换了这两个临时变量的值.
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值