Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.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
List 将列表作为函数参数传递,并从函数返回列表_List_Lisp_Common Lisp - Fatal编程技术网

List 将列表作为函数参数传递,并从函数返回列表

List 将列表作为函数参数传递,并从函数返回列表,list,lisp,common-lisp,List,Lisp,Common Lisp,我有以下代码: (defun read_coords (in) (setq x (read-line)) (if (equalp x "0") in (progn (append in (cons x nil)) (read_coords in) ) ) ) (setq coords (read_coords (cons nil nil))) 目标是读取输入行并将其存储在列

我有以下代码:

(defun read_coords (in)
    (setq x (read-line))
    (if (equalp x "0")
        in
        (progn
            (append in (cons x nil))
            (read_coords in)
        )
    )
)

(setq coords (read_coords (cons nil nil)))

目标是读取输入行并将其存储在列表中。问题是列表
coords
保持不变(因此只包含
NIL
)。我做错了什么?

append
不会修改它的参数,也就是说,因为您没有使用它的值,所以您没有做任何事情

(defun read-coords (&optional accumulation)
  (let ((x (read-line)))
    (if (string= x "0")
        (nreverse accumulation) ; done
        (read-coords (cons x accumulation)))))
(defvar *coords* (read-coords))

这是您的代码,具有更好的格式:

(defun read_coords (in)
  (setq x (read-line))
  (if (equalp x "0")
      in
      (progn
        (append in (cons x nil))
        (read_coords in))))

(setq coords (read_coords (cons nil nil)))
现在,
read\u coords
的返回值是多少?函数包含隐式,因此它是最后一种形式。这里,最后一个表单是。根据测试结果,返回值在位置为
,或在else位置为
PROGN
的返回值。因此,测试失败时的返回值是通过调用
(read_coords in)
获得的。当递归最终无误结束时,它必然位于
IF
的then分支中,该分支在
中返回
。请注意,
中的
在整个执行过程中从不被修改

事实上,它会根据输入创建一个新列表。换句话说,新列表是调用
APPEND
返回的值,不幸的是,它从未存储在任何地方。计算没有任何副作用,其结果被丢弃。 您可能应该这样做:

(read_coords (append in (cons x nil)))
因此,新列表将作为参数传递给递归调用

评论 不要使用来定义局部变量。您需要在这里使用a-binding。否则,您将以依赖于实现的方式更改全局词法范围(除非您定义了名为
x
的全局变量,这是不好的,因为它违反了特殊变量的命名约定,而特殊变量应该有
*耳罩*
)。在函数中对全局变量进行变异可能会使其不可重入,这是非常糟糕的

(cons x nil)
要使用一个元素构建列表,只需使用:

最后,请注意,名称中不应使用下划线,而应使用破折号。因此,您的函数应该命名为
read coords
,或者更好的命名为
read coordinates

(equalp x "0")
尽管上面的说法是正确的,但最好在这里使用
string=
,因为您知道返回字符串

演出 您一次又一次地追加一个列表,这将为正在读取的每个元素创建一个副本。对于一个可以用线性算法完成的任务,您的代码在时间和空间使用上是二次的。 此外,您正在使用一个尾部递归函数,其中一个简单的迭代将更清晰、更惯用。在公共Lisp中,我们通常不使用尾部递归过程,因为该语言提供了迭代控制结构,而且尾部合并优化不能保证总是应用(优化不是强制性的(这是一件好事)不会阻止实现提供它,即使它可能需要来自用户的附加声明)。最好在这里使用


我们在参数中传递一个输入流,该参数默认为。然后
READ-LINE
在忽略错误的情况下读取行(由于第一个零)。如果发现错误,比如当我们到达文件末尾时,返回的值是零(由于第二个零)。当正在读取的行为零或等于
“0”
时,
循环结束。循环将读取到列表中的所有连续行累加起来。

请修正缩进和排列。很抱歉,现在好点了吗?适度:-(请使用Emacs-它将正确缩进您的代码,并避免挂起括号。好的,我会试试;我不知道LISP编辑器,所以我使用常规notepadWow,这是一个很好的解释!我是LISP初学者,非常感谢您的努力:)@Karloss非常感谢。最好将
nreverse
调用放在函数中。
(list x)
(equalp x "0")
(defun read-coordinates (&optional (input-stream *standard-input*))
  (loop for line = (read-line input-stream nil nil)
        until (or (not line) (string= line "0"))
        collect line))