rest parameter 如何展开?

问个入门问题,关于rest参数

(defun fun1 (a &rest b)
  ...)

(defun fun2 (c &rest d)
  ...)

fun2 内部调用fun1的话,rest参数如何展开?

(defun fun2 (c &rest d)
  (fun1 c d)   ;; <= 直接这么调用不对吧?
  (fun1 c ...d) ;; ?? <= 也不通
  ...)
(defun fun2 (c &rest d)
  (apply 'fun1 c d))
1 个赞

好的,谢谢!一看就明白,但还不能熟练运用,和scheme不太一样。 :sweat_smile:

我寻思 Emacs Lisp 也有 ,@啊。

(eval `(fun1 c ,@d))

我现在处在学习中,还不能融会贯通,scheme我也只是做过练习。所以,对于lisp系语言,我还是新手。

有空的时候,就花点时间练习一下。目前在看awesome-pair的代码,并对齐进行重构,再改进一下。等重构完了,再追加新功能。每天没法花太多时间在lisp上,只能慢慢整。有几个我想要的功能,它没提供,所以,就从它入手。

我寻思我用的chez-scheme也有apply

大家不觉得scheme写起来,同样功能,代码量比cl多吗?

因为CL有一揽子特性。而且scheme的函数名普遍比较详细,不像cl那样基本就是魔法字符

比如说string->symbol vs. intern

RSR7现在没动静了吧?反正,大部分人是写elisp,规模不大。一般应用,还是golang,rust实用些。

啥,Scheme 也有 &rest

(define (fun1 a . b) ...)

为啥要用 eval

这两个完全不是一回事好吗,string->symbol 对标的是 make-symbolintern 比这两个多了 make symbol intern(al) to obarray ,某些 Scheme 实现也有 intern procedure,当然 Scheme 在标准设计上故意不让用户像 Lisp 那样直接用 String 存取 environment。同理因此 Scheme 不用 eval 也做不到 (funcall 'foo)

早就写完了,R8RS 都在出了。

不太懂Scheme标准设计,只能从实现上猜测用途。所以我看guile和chez都把string->symbol实现成类似intern的方式,就想当然了。(guile的uninterned symbol用make-symbol,chez倒是只有gensym

Scheme 只规定了 eq? 的很少的语义,没有规定 eq? 一定就是指针比较,也没规定什么是 intern 以至于 Chez 有个很诡异的特性。

> (set! sym (gensym))
> sym
#{g2 xz2wmui56faib0eyhaxb0-2}
> (eq? sym '#{g2 xz2wmui56faib0eyhaxb0-2})
#t
> (gensym? '#{foo 123})
#t

也就是说 gensym 的结果是 interned。或者说,其实直接把 eq? 实现成比较字面量而不是指针都不会有问题。

更绝的是 Chez 还能“更改事实”

> (gensym)
#{g0 ydx6vbp8s4eovam4munk2-0}
> '#{g1 ydx6vbp8s4eovam4munk2-1}
#{g1 ydx6vbp8s4eovam4munk2-1}
> (eq? '#{g1 ydx6vbp8s4eovam4munk2-1} '#{g1 ydx6vbp8s4eovam4munk2-1})
#t
> (set! foo '#{g1 ydx6vbp8s4eovam4munk2-1})
> (eq? foo '#{g1 ydx6vbp8s4eovam4munk2-1})
#t
> (set! bar (gensym))
> bar
#{g1 ydx6vbp8s4eovam4munk2-1}
> (eq? bar foo)
#f
> (eq? bar '#{g1 ydx6vbp8s4eovam4munk2-1})
#t
> (eq? foo
       '#{g1 ydx6vbp8s4eovam4munk2-1})
#f
> foo
#{g1 ydx6vbp8s4eovam4munk2-1}

在 CL 中,标准严格定义了 gensym 和 intern 的概念。

(eq '#:foo '#:foo) ;; => nil
3 个赞

&rest args 就是一个 List

不一定,你也没说 fun1 的参数必须和 fun2 一致。

(defun foo (&rest r)
  r)

((lambda (&rest r) (foo r)) 1 2 3)
;; => ((1 2 3))

((lambda (&rest r) (apply #'foo r)) 1 2 3)
;; => (1 2 3)

(eval ((lambda (&rest r) (cons 'foo r)) 1 2 3))
;; => (1 2 3)

我说要把参数“展开”了,从语法的角度,(fun1 c d)我知道是正确的。不过“展开”这个术语是否准确,就不清楚了。

从应用开发的角度,极少有人用cl或scheme开发。scheme做这个标准,是为了以后进军传统的开发市场?

大家学它们主要做什么?我现在也就写写elisp。

1 个赞

反正可以吧,多传个environment就是Scheme代码了。

和应用开发基本没关系,Scheme 本来就是用来研究 actor model 和 lambda calculus 的语言,现在也用来研究 meta programming 和编译器。

真要说应用的话,Scheme 是用来做胶水语言和脚本语言的。类似于 Python 的位置。

听说做的比较好的是chez,但它目前只支持到r6rs。

又处在什么位置呢?

开源以后没人管了。

Chez 就是设计用来做胶水语言的。