Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Lisp 推不工作,因为我会期待它-为什么?_Lisp_Common Lisp - Fatal编程技术网

Lisp 推不工作,因为我会期待它-为什么?

Lisp 推不工作,因为我会期待它-为什么?,lisp,common-lisp,Lisp,Common Lisp,我遇到了一个我没有得到的push函数的行为。也许有人可以向我解释为什么Lisp会这样做 假设我将列表定义为全局变量,然后尝试使用以下代码向其推送新值: (defparameter *primes* '(3 5 7 11)) (push 2 *primes*) 然后*素数*现在是(2 3 5 7 11)。到目前为止,一切顺利 现在我尝试做同样的事情,但没有*primes*变量,即: (push 2 '(3 5 7 11)) 结果是一条错误消息: EVAL:3不是函数名;尝试改用符号 现在我有两

我遇到了一个我没有得到的
push
函数的行为。也许有人可以向我解释为什么Lisp会这样做

假设我将列表定义为全局变量,然后尝试使用以下代码向其推送新值:

(defparameter *primes* '(3 5 7 11))
(push 2 *primes*)
然后
*素数*
现在是
(2 3 5 7 11)
。到目前为止,一切顺利

现在我尝试做同样的事情,但没有
*primes*
变量,即:

(push 2 '(3 5 7 11))
结果是一条错误消息:

EVAL:3不是函数名;尝试改用符号

现在我有两个问题:

  • 为什么这不起作用?我希望
    push
    返回列表
    (2 3 5 7 11)
    ,为什么不发生这种情况?我错在哪里
  • 除此之外,我没有收到错误信息。Lisp试图用
    3告诉我的不是函数名
    ?当然,
    3
    不是函数名,但我不会尝试在任何地方调用名为
    3
    的函数,是吗

  • 非常感谢您的帮助:-)

    我只找到了emacs lisp手册,但我想它的行为与Common lisp类似

    -宏:推送元素列表名

    此宏创建一个新列表,其car为元素,其cdr为listname指定的列表,并将该列表保存在listname中

    因此,
    push
    似乎正在修改它的参数
    listname
    ,这在文本列表中是不可能的。要做你想做的事,你可以使用
    cons

    对于第二部分,
    3不是一个函数名
    ,我想说
    push
    ,或者它里面的某个函数,尝试计算文本列表。求值
    (3 5 7 11)
    意味着使用参数
    5 7 11
    调用函数
    3
    。因此出现了错误消息


    再次从emacs,Ctrl-h f push

    push是'cl.el'中的Lisp宏

    (推X位)

    在存储的列表的开头插入X。
    类似于(setf位置(cons X位置)),但在 只对每个参数进行一次计算,并按正确的顺序进行计算。地点可能 可以是符号,也可以是“setf”允许的任何广义变量

    setf
    反过来允许
    place
    成为

    符号引用,如(car x)或(aref x i)


    这解释了为什么
    push
    计算第二个参数。

    如果您阅读了的CL Hyperspec for,您将看到
    push
    需要一个位置

    位置类似于变量、结构插槽、类插槽、数组访问等。由于Lisp使用链接的cons单元格作为列表,因此在cons单元格前面推送某些内容而没有引用是没有意义的

    所以上面很简单:我们不能推到直接列表。

    为什么会出现此错误消息?

    这有点复杂

    实际上是:

    (push 2 (quote (3 5 7 11))
    
    一个函数可以是一个位置,然后它需要一个相应的setter函数。这里的setter被认为是
    (setf quote)
    ——没错,Common Lisp有时可以将列表作为函数名,而不仅仅是符号

    如果我们看看上述的宏观扩张:

    ? (pprint (macroexpand '(push 2 (quote (3 5 7 11)))))
    
    (LET* ((#:G328 2) (#:G327 (3 5 7 11)) (#:G326 (CONS #:G328 '#:G327)))
      #:G327
      #:G326
      (FUNCALL #'(SETF QUOTE) #:G326 #:G327))
    
    您可以看到它试图调用setter。但它也认为
    (35711)
    是一种Lisp格式

    我给您举一个例子,它实际上是工作的,但我们不使用
    quote
    ,而是使用一个真正的访问器函数:

    CL-USER 40 > (let ((v (vector (list (list 'a 'b 'c) (list 'd 'e 'f))
                                  (list (list 1 2 3)    (list 4 5 6)))))
                   (print v)
                   (push 42 (first (aref v 1)))
                   (print v)
                   (values))
    
    #(((A B C) (D E F)) ((1 2 3) (4 5 6))) 
    #(((A B C) (D E F)) ((42 1 2 3) (4 5 6))) 
    
    在上面的
    中,first
    是getter,CL知道相应的setter。表单
    (arefv1)
    是调用并返回向量的索引1元素。然后我们推到元素的第一个列表


    您的呼叫具有类似的结构,并且
    (3 5 7 11)
    的位置与
    (aref v 1)
    相似。Lisp系统表示在
    (3 4 7 11)
    中,数字
    3
    不是有效的函数。这是正确的。但是真正的错误是关于
    push
    操作。由于宏无法检测到错误,因此稍后会在宏扩展代码中检测到错误。

    我认为第二种情况下需要
    CONS

    (cons 2 '(3 5 7 11)) => (2 3 5 7 11)
    

    CLHS
    push
    reference:对减号有何评论?
    (cons 2 '(3 5 7 11)) => (2 3 5 7 11)