(Common lisp) 扁平化和传递列表

(Common lisp) Flattening and passing list

我在这里要做的是首先展平任何给定的列表,然后将该列表传递到我的加密函数中。虽然这不起作用,但我不确定为什么。 这是我目前所拥有的,

(defun flatten (l)
  (cond ((null l) l)
       ((atom l) (list l))
      (t (loop for a in l appending (flatten a))))

)



(defun encrypt(enctext)
(flatten enctext)

  (if(eq 'A (first enctext))    ;If the first charcater equals 'A'...
      (progn                    ;To allow multiple statements in an if statement
       (princ #\B)              ; First statement, print this character
       (encrypt(rest enctext))))    ;Second statement, run function again passing the rest of the characters

  (if(eq 'B (first enctext))
      (progn
       (princ #\C)
        (encrypt(rest enctext))))


)

这就是我调用加密函数的方式

(encrypt '((A)(B))

我应该在 "encrypt" 函数中调用 "flatten" 函数吗?或者在递归调用之后在 "flatten" 函数中调用 "encrypt"? 我将如何正确传递扁平化列表?

FLATTEN 不会破坏性地修改列表。它创建一个包含扁平化内容的新列表。您必须使用它的 return 值而不是原来的 ENCTEXT。这很容易通过调用 ENCRYPT 来实现:

(encrypt (flatten '((A) (B))))

并从 ENCRYPT 中删除对 FLATTEN 的调用。这是您的代码的更简洁版本:

(defun encrypt (enctext)
  (unless (endp enctext)
    (princ (ecase (first enctext) ; I'm assuming the input shouldn't 
             (A #\B)              ; contain any symbols that aren't
             (B #\C)))            ; handled here. Otherwise use CASE
    (encrypt (rest enctext))))    ; instead of ECASE.

如果您想在不调用单独的函数来展平列表的情况下执行此操作,则需要递归下降到 ENCRYPT 内的输入列表。类似于:

(defun encrypt (enctext)
  (unless (endp enctext)
    (let ((first (first enctext)))
      (if (atom first)
          (princ (ecase first
                   (A #\B)
                   (B #\C)))
          (encrypt first)))
    (encrypt (rest enctext))))

(encrypt '((A) (B)))
; BC

当然,如果您没有理由想要对深度和广度都使用递归来执行此操作,则循环会使代码更清晰:

(defun encrypt (enctext)
  (dolist (el enctext)
    (if (atom el)
        (princ (ecase el
                 (A #\B)
                 (B #\C)))
        (encrypt el))))