[英]Lisp loop macro, pop macro and memory
I'm learning lisp and and implemented a nested array parses, so that:我正在学习 lisp 并实现了嵌套数组解析,因此:
"[1,[2,[3,[4,[5,6,7]]]],8,9]" -> '(1 (2 (3 (4 (5 6 7)))) 8 9)
Online Code snippet here在线代码片段在这里
This was my first implementation of parse-line
这是我第一次实现
parse-line
(defun parse-line (string)
(loop
:for i = 0 :then (1+ j)
:for stack = (list nil)
:as j = (position-if (lambda (c) (member c '(#\[ #\] #\,))) string :start i)
:as n = (parse-integer string :start i :end j :junk-allowed t)
:when n :do (push n (car stack))
:while j
:do (cond
((eql #\[ (aref string j)) (push nil stack))
((eql #\] (aref string j)) (push (nreverse (pop stack)) (car stack))))
:finally (return (car (pop stack))))
))
But it crashes on the stack pop.但它在堆栈弹出时崩溃。
;test-case
(print (equal '(1 (2 (3 (4 (5 6 7)))) 8 9) (parse-line "[1,[2,[3,[4,[5,6,7]]]],8,9]")))
The value NIL is not of type CONS
值 NIL 不是 CONS 类型
I then brute-forced my way into a solution declaring stack
with let
outside the loop
macro然后
let
强行进入一个解决方案,在loop
宏之外声明stack
(defun parse-line (string)
(let ((stack (list nil)))
(loop
:for i = 0 :then (1+ j)
:as j = (position-if (lambda (c) (member c '(#\[ #\] #\,))) string :start i)
:as n = (parse-integer string :start i :end j :junk-allowed t)
:when n :do (push n (car stack))
:while j
:do (cond
((eql #\[ (aref string j)) (push nil stack))
((eql #\] (aref string j)) (push (nreverse (pop stack)) (car stack))))
:finally (return (car (pop stack))))
))
But I can't see why the second implementation works.但我不明白为什么第二个实现有效。
I also can't see why I need to initialize stack
with (list nil)
.我也不明白为什么我需要用
(list nil)
初始化stack
。 I thought that initializing stack
to nil
and removing the final car
should be equivalent but it crashes with the same error at the same place, ie:我认为将
stack
初始化为nil
并删除最终的car
应该是等效的,但它在同一位置因相同的错误而崩溃,即:
(defun parse-line (string)
(let (stack)
(loop
:for i = 0 :then (1+ j)
:as j = (position-if (lambda (c) (member c '(#\[ #\] #\,))) string :start i)
:as n = (parse-integer string :start i :end j :junk-allowed t)
:when n :do (push n (car stack))
:while j
:do (cond
((eql #\[ (aref string j)) (push nil stack))
((eql #\] (aref string j)) (push (nreverse (pop stack)) (car stack))))
:finally (return (pop stack)))
))
Look at these two lines in your first implementation:在您的第一个实现中查看这两行:
:for i = 0 :then (1+ j)
:for sack = (list nil)
There is a typo ( sack -> stack ), but even then it doesn't work, because with each new value of i
, you will create a brand new stack
, losing all previous values.有一个错字( sack -> stack ),但即使那样它也不起作用,因为对于
i
的每个新值,您将创建一个全新的stack
,丢失所有以前的值。 Add some debug print to see, what's going on:添加一些调试打印以查看发生了什么:
i:0 j:0 n:NIL stack:(NIL NIL)
i:1 j:2 n:1 stack:((1))
i:3 j:3 n:NIL stack:(NIL NIL)
i:4 j:5 n:2 stack:((2))
i:6 j:6 n:NIL stack:(NIL NIL)
i:7 j:8 n:3 stack:((3))
...
If you don't want to use let
to initialize stack
, you can use keyword :with
:如果你不想使用
let
来初始化stack
,你可以使用关键字:with
:
(defun parse-line (string)
(loop
:with stack = (list nil)
:for i = 0 :then (1+ j)
:as j = (position-if (lambda (c) (member c '(#\[ #\] #\,))) string :start i)
:as n = (parse-integer string :start i :end j :junk-allowed t)
:when n :do (push n (car stack))
:while j
:do (cond
((eql #\[ (aref string j)) (push nil stack))
((eql #\] (aref string j)) (push (nreverse (pop stack)) (car stack))))
:finally (return (car (pop stack)))))
You can use a similar debug print to see, why your code crashes with stack
initialized to nil
.您可以使用类似的调试打印来查看为什么您的代码在
stack
初始化为nil
时崩溃。 This error can be reproduced with:此错误可以通过以下方式重现:
> (let ((stack '((9 8 (2 (3 (4 (5 6 7)))) 1))))
(push (nreverse (pop stack)) (car stack)))
Error: NIL (of type NULL) is not of type CONS.
You can find some explanation for this behaviour here: Why I can't (push 3 '()) in Common Lisp's REPL?您可以在此处找到有关此行为的一些解释: Why I can't (push 3 '()) in Common Lisp's REPL?
I would recommend using a Lisp compiler and using its warnings.我建议使用 Lisp 编译器并使用它的警告。 SBCL gives this warning on your first form:
SBCL 在您的第一份表格中给出此警告:
; in: DEFUN PARSE-LINE
; (PUSH N (CAR STACK))
;
; caught WARNING:
; undefined variable: COMMON-LISP-USER::STACK
;
; compilation unit finished
; Undefined variable:
; STACK
; caught 1 WARNING condition
That would lead you to investigate why that is: why is STACK undefined?这将引导您调查原因:为什么 STACK 未定义?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.