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

时间:2016-12-02 18:47:57

标签: 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)))

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

2 个答案:

答案 0 :(得分:5)

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

(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_coords的返回值是多少?函数包含隐式PROGN,因此它是最后一种形式。在这里,最后一个表格是IF。根据测试结果,返回值为in else 位置的PROGN的返回值。因此,测试失败时的返回值是通过调用(read_coords in)获得的值。当递归最终没有错误结束时,它必然位于IF then 分支中,返回in请注意,in在整个执行期间永远不会被修改

确实,APPEND根据其输入创建了一个新的列表。换句话说,新列表是对APPEND的调用返回的值,遗憾的是,它永远不会存储在任何地方。计算完成没有任何副作用,其结果被丢弃。 你应该这样做:

(read_coords (append in (cons x nil)))

因此,新列表将作为参数传递给递归调用。

说明

(setq x (read-line))

不要使用SETQ来定义局部变量。你需要在这里使用LET - 绑定。否则,您将以与实现相关的方式更改全局词法作用域(除非您定义了一个名为x的全局变量,这是不好的,因为它违反了特殊变量的命名约定,它应该具有{{1 }})。在函数内部变换全局变量使其可能不可重入,这非常糟糕。

*earmuffs*

要使用一个元素构建列表,只需使用LIST

(cons x nil)

最后,请注意,您没有在名称中使用下划线,更喜欢破折号。因此,您的函数应该命名为(list x) ,或者更好,read-coords

read-coordinates

即使上面的内容是正确的,最好在这里使用(equalp x "0") ,因为您知道READ-LINE会返回一个字符串。

效果

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

string=

我们在参数中传递输入流,默认为*STANDARD-INPUT*。然后(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)) 读取行而忽略错误(感谢第一个NIL)。如果发现错误,例如当我们到达文件结尾时,返回的值是NIL(由于第二个NIL)。当读取的行是NIL或等于READ-LINE时,LOOP结束。循环将所有连续的行累积到列表中。

答案 1 :(得分:3)

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))