emacs lisp的奇怪问题,关于pop

15 views
Skip to first unread message

池塘仙人

unread,
Mar 5, 2012, 1:27:19 AM3/5/12
to Lisp-cn(Lisp中文用户组)
(defun my-pop (a)
(pop a));my-pop无法正常运行
(defun test ()
(let ((a '(1 2)) (b '(1)) (c '(1 2)) (d '(1)))
(pop a)
(print a);(2) ok
(pop b)
(print b);nil ok
(my-pop c)
(print c);(2) ok
(my-pop d)
(print d);(1) pop 失败
)
)
setcar、setcdr之类的就不会有这样的问题,囧

刘滔

unread,
Mar 5, 2012, 2:08:57 AM3/5/12
to lis...@googlegroups.com
真奇怪,我在自己的Emacs上运行了test函数后,(print d)确实是打印了nil到minibuffer中的。


--
Lisp-cn(Lisp中文用户组)
CLUG http://lisp.org.cn



--
Liutos Love Linux LaTeX Lisp Ling

我的博客,纪念我死去的GAE

池塘仙人

unread,
Mar 5, 2012, 6:23:42 AM3/5/12
to Lisp-cn(Lisp中文用户组)
这是我凭记忆写的,回家的时候又测试了一下,版本是GNU Emacs 23.3.1

我原来给的结果不对,实际结果是这样的

(defun my-pop (a)
(pop a));my-pop无法正常运行
(defun test ()
(let ((a '(1 2)) (b '(1)) (c '(1 2)) (d '(1)))
(pop a)
(print a);(2) ok
(pop b)
(print b);nil ok
(my-pop c)

(print c);(1 2) pop 失败,情况统一,应该不是bug
(my-pop d)
(print d);(1) pop 失败 ,情况统一,应该不是bug
)
)

我分析原因,你大概用了smile,其实是common lisp,pop使用了setf,所以会影响外部,而emasc lisp里是setq,影响
不到外部--

我原来的实际例子是这样的

(defun remove-last (heap)
(if (null heap)
nil
(let ((temp (nreverse heap)))
(prog1 (pop temp)
(nreverse temp)))))

(defun test ()
(let ((a '(1 2)) (b '(1)) (c '(1 2)) (d '(1)))
(pop a)
(print a);(2) ok
(pop b)
(print b);nil ok

(remove-last c)
(print c);(1) remove-last成功
(remove-last d)
(print d);(1) remove-last失败
)
)

这就不奇怪了,长度为1时,pop以后变成nil了,nreverse失效了,所以出bug了

不过奇怪的事情又出现了,本来影响不到外部的pop,因为nreverse又能影响外部了

On Mar 5, 3:08 pm, 刘滔 <mat.liu...@gmail.com> wrote:
> 真奇怪,我在自己的Emacs上运行了test函数后,(print d)确实是打印了nil到minibuffer中的。
>

> 在 2012年3月5日 下午2:27,池塘仙人 <yourname1...@gmail.com>写道:
>
>
>
>
>
>
>
>
>
> > (defun my-pop (a)
> > (pop a));my-pop无法正常运行
> > (defun test ()
> > (let ((a '(1 2)) (b '(1)) (c '(1 2)) (d '(1)))
> > (pop a)
> > (print a);(2) ok
> > (pop b)
> > (print b);nil ok
> > (my-pop c)
> > (print c);(2) ok
> > (my-pop d)
> > (print d);(1) pop 失败
> > )
> > )
> > setcar、setcdr之类的就不会有这样的问题,囧
>
> > --
> > Lisp-cn(Lisp中文用户组)

> > CLUGhttp://lisp.org.cn


>
> --
> Liutos Love Linux LaTeX Lisp Ling
>

> 我的博客,纪念我死去的GAE <http://blog.sina.com.cn/u/2031941547>

刘滔

unread,
Mar 5, 2012, 6:54:14 AM3/5/12
to lis...@googlegroups.com
 呃,我真的是在Emacs里面用Elisp尝试的,真的没有用SLIME,也不是Common Lisp……

不过我也犯了一个错误,我之前尝试的那个test函数里面的pop用的是pop而不是my-pop,现在尝试了my-pop的版本,minibuffer的打印结果为

(2)

nil

(1 2)

(1)

确实,作为在函数里面的pop是影响不到外面的,就算是在Common Lisp里面也不能改变外面的值,因为作为参数传进去的那个已经只是一个值了,而不是符号,pop在宏展开的时候已经找不到那个符号了,自然无法改变那个值。


--
Lisp-cn(Lisp中文用户组)
CLUG http://lisp.org.cn

池塘仙人

unread,
Mar 5, 2012, 7:16:25 AM3/5/12
to Lisp-cn(Lisp中文用户组)
那为什么和nreverse一起使用的时候,又会影响到外面呢,求指点

On Mar 5, 7:54 pm, 刘滔 <mat.liu...@gmail.com> wrote:
> 呃,我真的是在Emacs里面用Elisp尝试的,真的没有用SLIME,也不是Common Lisp......
>
> 不过我也犯了一个错误,我之前尝试的那个test函数里面的pop用的是pop而不是my-pop,现在尝试了my-pop的版本,minibuffer的打印 结果为


>
> (2)
>
> nil
>
> (1 2)
>
> (1)
>
> 确实,作为在函数里面的pop是影响不到外面的,就算是在Common
> Lisp里面也不能改变外面的值,因为作为参数传进去的那个已经只是一个值了,而不是符号,pop在宏展开的时候已经找不到那个符号了,自然无法改变那个值。
>

刘滔

unread,
Mar 5, 2012, 8:54:37 AM3/5/12
to lis...@googlegroups.com
我只在Common Lisp里面用过nreverse函数。我觉得这个东西是不能用定义函数来实现的,因为这个函数有副作用,它会真真正正地改变传递给它的参数,类似的还有delete函数,返回值和remove一样,只是它的效果是in place的,也就是作为参数传递的值会被修改,就是有side effect,副作用。

--
Lisp-cn(Lisp中文用户组)
CLUG http://lisp.org.cn

池塘仙人

unread,
Mar 5, 2012, 9:21:15 AM3/5/12
to Lisp-cn(Lisp中文用户组)
虽然nreverse有副作用,但是不过pop本身效果不能传到函数外,那调用两次nreverse也应该只是变回原来的列表吧

On Mar 5, 9:54 pm, 刘滔 <mat.liu...@gmail.com> wrote:
> 我只在Common

> Lisp里面用过nreverse函数。我觉得这个东西是不能用定义函数来实现的,因为这个函数有副作用,它会真真正正地改变传递给它的参数,类似的还有del ete函数,返回值和remove一样,只是它的效果是in


> place的,也就是作为参数传递的值会被修改,就是有side effect,副作用。
>

刘滔

unread,
Mar 5, 2012, 10:29:39 AM3/5/12
to lis...@googlegroups.com
理解不能了,我自己都乱掉了……

--
Lisp-cn(Lisp中文用户组)
CLUG http://lisp.org.cn

无很

unread,
Mar 5, 2012, 9:02:05 PM3/5/12
to lisp-cn
从运行结果来看应该和c,Java等语言的传值或传引用问题类似,但有一点我也不太明白,my-pop中的参数a到底绑定值了吗?我用(boundp 'a)得到的是nil,想取a的值用(symbol-value 'a)报错"a 未绑定".
我想应该是a重新绑定了 '(1 2)和(1) 执行pop操作后并不影响原来c或d的值,所以结果是(1 2),(1) . 但我用boundp和symbol-value测试让我迷惑了.
请高手解答!!
 
 
2012-03-06

无很

发件人: 池塘仙人
发送时间: 2012-03-05  19:23:57
收件人: Lisp-cn(Lisp中文用户组)
抄送:
主题: [Lisp-cn] Re: emacs lisp的奇怪问题,关于pop
这是我凭记忆写的,回家的时候又测试了一下,版本是GNU Emacs 23.3.1
我原来给的结果不对,实际结果是这样的
(defun my-pop (a)
  (pop a));my-pop无法正常运行
(defun test ()
  (let ((a '(1 2)) (b '(1)) (c '(1 2)) (d '(1)))
    (pop a)
    (print a);(2) ok
    (pop b)
    (print b);nil ok
    (my-pop c)
    (print c);(1 2) pop 失败,情况统一,应该不是bug
    (my-pop d)
    (print d);(1) pop 失败 ,情况统一,应该不是bug
  )
)
我分析原因,你大概用了smile,其实是common lisp,pop使用了setf,所以会影响外部,而emasc lisp里是setq,影响
不到外部--
我原来的实际例子是这样的
(defun remove-last (heap)
    (if (null heap)
nil
      (let ((temp (nreverse heap)))
(prog1 (pop temp)
  (nreverse temp)))))
(defun test ()
  (let ((a '(1 2)) (b '(1)) (c '(1 2)) (d '(1)))
    (pop a)
    (print a);(2) ok
    (pop b)
    (print b);nil ok
    (remove-last c)
    (print c);(1) remove-last成功
    (remove-last d)
    (print d);(1) remove-last失败
  )
)
这就不奇怪了,长度为1时,pop以后变成nil了,nreverse失效了,所以出bug了
不过奇怪的事情又出现了,本来影响不到外部的pop,因为nreverse又能影响外部了
On Mar 5, 3:08 pm, 刘滔 <mat.liu...@gmail.com> wrote:
> 真奇怪,我在自己的Emacs上运行了test函数后,(print d)确实是打印了nil到minibuffer中的。
>
> 在 2012年3月5日 下午2:27,池塘仙人 <yourname1...@gmail.com>写道:
>
>
>
>
>
>
>
>
>
> > (defun my-pop (a)
> >  (pop a));my-pop无法正常运行
> > (defun test ()
> >  (let ((a '(1 2)) (b '(1)) (c '(1 2)) (d '(1)))
> >    (pop a)
> >    (print a);(2) ok
> >    (pop b)
> >    (print b);nil ok
> >    (my-pop c)
> >    (print c);(2) ok
> >    (my-pop d)
> >    (print d);(1) pop 失败
> >  )
> > )
> > setcar、setcdr之类的就不会有这样的问题,囧
>
> > --
> > Lisp-cn(Lisp中文用户组)
> > CLUGhttp://lisp.org.cn
>
> --
> Liutos Love Linux LaTeX Lisp Ling
>
> 我的博客,纪念我死去的GAE <http://blog.sina.com.cn/u/2031941547>

Xiaosong Sun

unread,
Mar 5, 2012, 9:57:29 PM3/5/12
to lis...@googlegroups.com
第一,nreverse这样的破坏性函数的用法不是这样的,想翻转x,必须(setq x (nreverse x))。比如说x是(1 2
3),如果单纯地(nreverse x),操作过后剩下的x的值是(1),不是(3 2
1)。从这点来说,remove-last的用法是不对的。
第二,pop是个macro,跟函数不一样。函数参数当然是传引用,或者说,传递的是“指针的拷贝”。要想达到同样的效果,my-pop也应该定义为macro。
第三,remove-last不一定非得自己实现啊,用(setq x (butlast x))也可以的。

关于wuhen说的参数未绑定问题,我不太确定是什么情况。请问你是怎么测试的啊。

无很

unread,
Mar 5, 2012, 10:04:00 PM3/5/12
to lisp-cn
我是在my-pop中使用boundp测试形参a,得到nil .用symbol-value 报错.
我刚明白boundp和symbol-value只能用于全局变量,不好意思!
 
 
 
 
2012-03-06

无很

发件人: Xiaosong Sun
发送时间: 2012-03-06  10:57:46
收件人: lisp-cn
抄送:
主题: Re: [Lisp-cn] Re: emacs lisp的奇怪问题,关于pop

Xiaosong Sun

unread,
Mar 5, 2012, 11:12:32 PM3/5/12
to lis...@googlegroups.com
wuhen,你用的是common lisp吧?楼主讨论时用的是elisp。
至少在elisp的文档里边,boundp和symbol-value是可以用于测试lexical
binding的变量的。或者说,在elisp实现中,这两个函数作用于最内层的上下文。

刘滔

unread,
Mar 5, 2012, 11:31:27 PM3/5/12
to lis...@googlegroups.com
symbol-value是用来测试全局定义的符号的,作为remove-last的参数的符号a当然没有绑定也没有符号对应的值了。

Xiaosong Sun

unread,
Mar 5, 2012, 11:47:16 PM3/5/12
to lis...@googlegroups.com
以下摘自elisp文档,大家讨论的时候都完全基于经验主义和实践主义么?
再说楼主的题目就是关于emacs lisp的。。。

-- Function: symbol-value symbol
This function returns the value of SYMBOL. This is the value in
the innermost local binding of the symbol, or its global value if
it has no local bindings.

(setq abracadabra 5)
=> 5
(setq foo 9)
=> 9

;; Here the symbol `abracadabra'
;; is the symbol whose value is examined.
(let ((abracadabra 'foo))
(symbol-value 'abracadabra))
=> foo

;; Here, the value of `abracadabra',
;; which is `foo',
;; is the symbol whose value is examined.
(let ((abracadabra 'foo))
(symbol-value abracadabra))
=> 9

(symbol-value 'abracadabra)
=> 5

刘滔

unread,
Mar 6, 2012, 3:56:55 AM3/6/12
to lis...@googlegroups.com
我错了,真没看文档,我确实是在用CL的想法看Elisp……

Xiaofeng Yang

unread,
Mar 6, 2012, 5:53:02 AM3/6/12
to lis...@googlegroups.com
你们真强大,两个完全不搭嘎得语言讨论的这么欢乐。


     Best regards,
Xiaofeng Yang

刘滔

unread,
Mar 6, 2012, 6:05:58 AM3/6/12
to lis...@googlegroups.com
哈哈,因为有共性嘛,我也是用Elisp来理解那些代码的,尽管可能不太一样~

Xiaofeng Yang

unread,
Mar 6, 2012, 6:26:15 AM3/6/12
to lis...@googlegroups.com
完全就是完全不搭嘎的两种语言。




     Best regards,
Xiaofeng Yang
Reply all
Reply to author
Forward
0 new messages