List Lisp中的十进制到二进制-创建非嵌套列表

List Lisp中的十进制到二进制-创建非嵌套列表,list,recursion,binary,lisp,List,Recursion,Binary,Lisp,当到达递归案例时,我使用list将未来结果附加到当前结果,但由于递归,我最终得到了一个嵌套列表。当我有一个导致递归超过五次的数字时,这会导致一个错误 我如何在一个简单的非嵌套列表中获得结果,例如: CL-USER 100:8>(二进制列表4) (100) 代码和示例输出: CL-USER 99 : 8 > (defun binary_list (i) (COND ((= i 0) 0) ((= i 1) 1) ((= (mod i 2) 0) (list (bin

当到达递归案例时,我使用
list
将未来结果附加到当前结果,但由于递归,我最终得到了一个嵌套列表。当我有一个导致递归超过五次的数字时,这会导致一个错误

我如何在一个简单的非嵌套列表中获得结果,例如:

CL-USER 100:8>(二进制列表4)

(100)

代码和示例输出:

CL-USER 99 : 8 > (defun binary_list (i)
(COND 
    ((= i 0) 0)
    ((= i 1) 1)
    ((= (mod i 2) 0) (list (binary_list (truncate i 2)) 0))
    (t (list (binary_list (truncate i 2)) 1))
    )
)
BINARY_LIST

CL-USER 100 : 8 > (BINARY_LIST 4)
((1 0) 0)

CL-USER 101 : 8 > (BINARY_LIST 104)
((((# 1) 0) 0) 0)

你就快到了。您需要做的只是替换为:

通过以整数除法收集两个值,可以避免同时调用和:

(defun binary-list (n)
  (assert (>= n 0))
  (multiple-value-bind (q r) (floor n 2)
    (if (zerop q)
        (list r)
        (nconc (binary-list q) (list r)))))
请注意,此算法是二次的,因为每次迭代都必须遍历结果。这可以通过传递累加器来避免:

(defun binary-list (n &optional acc)
  (assert (>= n 0))
  (multiple-value-bind (q r) (floor n 2)
    (if (zerop q)
        (cons r acc)
        (binary-list q (cons r acc)))))
现在我们有了一个尾部递归函数,它可以被现代编译器编译成迭代

您可以使用的另一个优化技巧(事实上,这应该由编译器完成-请尝试检查!)是使用and,而不是更通用、更昂贵的:


顺便说一句,Lisper通常在符号中使用破折号而不是下划线,因此如果您不想冒犯我们的投标美学,您的
二进制列表应该是
二进制列表。

在我看来,这似乎是每次都能达到预期效果的最直接、最不迂回的方式:

(defun mvp-binary-from-decimal (n r)
    (if (zerop n)
    r
    (multiple-value-bind (a b)
        (floor n 2)
        (mvp-binary-from-decimal a (cons b r)))))

(defun binary-from-decimal (n)
    (if (and (numberp n) (plusp n))
    (mvp-binary-from-decimal n '())
    (if (eql n 0) '(0) nil)))
在煤泥、sbcl、clisp中测试-使用如下:

CL-USER> (binary-from-decimal 100)
(1 1 0 0 1 0 0)
CL-USER> (binary-from-decimal 10)
(1 0 1 0)
CL-USER> (binary-from-decimal 0)
(0)

关于为什么这可能是实现此类功能最理想的方式,有一些高级原因,但现在,只需说它干净、礼貌、可读并且总是有效。

您能解释一下提示的含义吗
CL-USER 101:8>
?尤其是
8
?您应该看看。这是基于球拍的,但技术仍然适用。谢谢@JoshuaTaylor的链接。至于“CL-USER 100:8>”,这是在的命令行中指定的COMMON-LISP-USER包。我认为
8
意味着用户没有从8个(!)级别的错误中中止。
(defun mvp-binary-from-decimal (n r)
    (if (zerop n)
    r
    (multiple-value-bind (a b)
        (floor n 2)
        (mvp-binary-from-decimal a (cons b r)))))

(defun binary-from-decimal (n)
    (if (and (numberp n) (plusp n))
    (mvp-binary-from-decimal n '())
    (if (eql n 0) '(0) nil)))
CL-USER> (binary-from-decimal 100)
(1 1 0 0 1 0 0)
CL-USER> (binary-from-decimal 10)
(1 0 1 0)
CL-USER> (binary-from-decimal 0)
(0)