(Common lisp)展平和传递列表

时间:2016-05-01 03:17:20

标签: lisp common-lisp clisp

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

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

我应该在“加密”功能中调用“展平”功能吗?或者在递归调用后在“flatten”函数中调用“encrypt”? 我将如何正确地通过扁平列表?

1 个答案:

答案 0 :(得分:1)

FLATTEN不会破坏性地修改列表。它会创建一个包含展平内容的新列表。您必须使用其返回值而不是原始ENCTEXT。这可以通过调用ENCRYPT来轻松实现:

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

FLATTEN移除对ENCRYPT的来电。这是一个更简洁的代码版本:

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