一直没有搞懂,common lisp为什么用把函数和变量放在不同的命名空间?

这回是你云了吧

image

Elisp为了模拟这个诡异的行为还费了不少心思

我说了外面有 defun 了么?

我只说了 flet labels 定义的局部函数,用不用 funcall,加不加 #’ 都能调用。

Emacs 要特殊处理不过是因为 emacs lisp 里 #’ 和 quote 在多数情况下作用几乎是等价的。而 Common Lisp 里的作用是返回函数指针罢了

你那里举的例子就很有迷惑性好吧。

用elisp是因为他用macro实现的,看起来比较具象化。

另外用funcall的话不用sharpquote还就不能调用。如果没有defun那个fun

(flet ((fun () 1)) (funcall 'fun))

会报错

帮你举了,quote和sharpquote在flet系(flet*, labels)里语义还是有丁点不同的。

那得怎么举?

所以为啥funcall函数对象和符号还有区别?

因为变量和函数在两个命名空间… 然后,defvar一个变量,然后你可以把匿名函数丢给它,但变量名不在函数那块儿,(function xx)取不到值,也无法(xx )直接调用,得(funcall xx)。这在把函数当参数传的时候经常用。

labels的作用,在scheme里基本可以靠let实现的(当然scheme 局部define就好了,还少一个缩进代码更整齐),cl因为函数要单独放#'能取到,所以let和labels flet都有。

Description:

funcall applies function to args . If function is a symbol , it is coerced to a function as if by finding its functional value in the global environment .

本来在 MacLisp 和 Emacs Lisp 类似,是没有 #’ 的,Lisp Machine 上实现成有区别了,于是 CL 标准就定义成这样了。Lisp Machine 这样做的理由是 #’ 可以编译时确定,’ 是运行时的,为了效率只看 global binding。

2 个赞

所以你不知道 Scheme 的 letrec 是干啥的?

嘛,本来想说“要不我改掉labels” 或者 “let系嘛,哈哈哈哈flet系好了”。 不过letrec不用也罢。

(let ((balala 'i-am-null))
  (let ((oh-my-balala (lambda (n) 
                          (if (= n 0)  
                             "Zzzzz...."
                             (balala (- n 1))))))
     (set! balala oh-my-balala)
     (balala 10)))

不想用 letrecdefine 不就行了

(define (test)
      (define (fib x)
        (case x
          [0 1]
          [1 1]
          [else (+ (fib (1- x)) (fib (- x 2)))]))
      fib)

(test)
;; #<procedure fib>
fib
;; Exception: variable fib is not bound

这就赖皮了,说好let。

scheme就这儿好,东西少包也少,太大的的事儿干不了,拿来实现各种实用函数,简单明了。

搞不好再过十几年,剩下的lisp只有scheme…

现实中的fib绝对不会是那样的定义

只能说是个玩具

有缓存结果的方法吗? 虽说和letrec没关系,我觉得还是普及一下比较好!

你不普及 我不勉强 大家可以看 RealWorldOcaml 里的例子

可以用fib stream(惰性求值),写出来和naive的长得差不多。

1 个赞

尾递归呀 不格式化了哈好麻烦

(define (fib n)

(define (iter a b counter)

 (if (= counter 0)
    b
    (iter (+ a b)
          a
          (- counter 1))))

(iter 1 0 n))

那 fib 250 之后 再求 fib 251 他是不是秒回呢?

naive 是什么样子的呢?

naive 就是我写的那个

fib stream 用 Haskell 写就是

fib = map fib' [0..] !!
  where fib' 0 = 1
        fib' 1 = 1
        fib' n = fib (n-1) + fib (n-2)

Haskell 多了层 CAF 就会自动 mem 了。虽然咋看起来很方便,不过偶尔也会导致内存泄漏罢了。

我不写尾递归是因为 Axiom/FriCAS 不需要任何 hint 就能自动把 naive 版本转化成 loop。而且 mem 也是自动做的。你们用笨蛋编译器管我什么事咯。

不看好,因为 Scheme 的特性导致不会有什么 Scheme 写的项目能长久留存。而且我看这社区的尿性再过几年 Scheme 就把自己开除 Lisp 了。Scheme 和 Prolog, SML, Haskell 一样,都是一开始用 Lisp 实现的语言,你看这三个现在哪有标榜自己是 Lisp 的?

顺带,letrec 是 primitive,mutation 反而是可以避免的万恶之源。

好吧 出现了个新的问题

有谁能讨论 Haskell 吗?

看完紫书就可以看 functional pearls 了,讨论无意义,就是为了自己爽罢了。自从我发现语出惊人之流自己也不能免俗,(比如 PG 发明了 Blub Paradox 吹 macro,结果自己还是不免对 OOP 有偏见,再比如某yin)我就不怎么管自己说了什么了。