Recursion 不确定为什么let函数不是';t在sbcl lisp中正确返回值

Recursion 不确定为什么let函数不是';t在sbcl lisp中正确返回值,recursion,lisp,common-lisp,sbcl,Recursion,Lisp,Common Lisp,Sbcl,因此,我编写了一个函数,根据无序对的“值”(对的第二部分)对列表进行排序。下面是我对递归函数的尝试(我知道它有一个基本的设计): *编辑功能设计:该功能通过以下方式工作: 获取无序对列表、已排序频率列表和递归调用的可选惊奇列表。它首先将listRet设置为等于惊吓者 如果无序列表只有一个元素,则该元素将被推送到listRet 如果列表大于1,则循环遍历每对无序列表,并检查其是否等于有序频率列表的第一个元素 如果它不是最后一个元素,则将其推送到listRet 然后循环继续,直到它到达最后一个元素,

因此,我编写了一个函数,根据无序对的“值”(对的第二部分)对列表进行排序。下面是我对递归函数的尝试(我知道它有一个基本的设计):

*编辑功能设计:该功能通过以下方式工作:

  • 获取无序对列表、已排序频率列表和递归调用的可选惊奇列表。它首先将listRet设置为等于惊吓者

  • 如果无序列表只有一个元素,则该元素将被推送到
    listRet

  • 如果列表大于1,则循环遍历每对无序列表,并检查其是否等于有序频率列表的第一个元素

  • 如果它不是最后一个元素,则将其推送到listRet

  • 然后循环继续,直到它到达最后一个元素,然后递归调用该函数,并从无序列表中删除推送对,因为它已正确放置在listRet和最高频率中。listRet作为可选的startList参数放置到位

  • 现在,如果无序列表有多个元素,并且最后一个元素是正确的排序频率,我选择将该元素移动到列表的前面,并进行递归调用

  • 无序列表的第一个元素现在可以被删除,然后我滥用do循环到达列表的末尾,再次进行递归函数调用,如步骤5所示

  • 第一个If语句在无序列表的长度为1之后退出(如步骤2所示),并且应该返回
    listRet

  • 功能:

    (defun sort-by-freq (listUnord listOrdFreqs &optional startList)
      (print startList)
      (let ((listRet startList)) ;; step 1
         (if (equal (length listUnord) 1) ;;step 2
             ;;(print listRet)
             (push (car listUnord) listRet)
             (loop for pair in listUnord ;;step 3
               do (if (and (equal (cdr pair) (car listOrdFreqs)) 
                           (not (equal (last-element-by-pair listUnord)(car pair))))
                      (push pair listRet) ;;step 4
                      (if (and (equal (cdr pair) (car listOrdFreqs))
                               (equal (last-element-by-pair listUnord)(car pair))) 
                          (sort-by-freq (append (list (cons (car pair) (cdr pair)))
                                                (remove-element listUnord pair)) 
                                        listOrdFreqs listRet) ;;step 6
                         (if (equal (last-element-by-pair listUnord)(car pair))
                             (sort-by-freq (remove-element listUnord (car listRet))
                                           (cdr listOrdFreqs)
                                           listRet)))))) ;; step 5
      listRet)) ;;step 8
    
    因此,如果我打电话:

    (sort-by-freq (list(cons 'c 2)(cons 'b 3)(cons 'a 1)) '(3 2 1))
    
    我期望结果是:

    ((A . 1) (C . 2) (B . 3)) 
    
    但出于某种原因,我得到的回报只有:

    ((B . 3)) 
    
    使用
    (print startList)
    语句,我可以确认startList正在按我所希望的那样构建。它输出:

    NIL 
    ((B . 3)) 
    ((B . 3)) 
    ((C . 2) (B . 3)) 
    
    我已经通过注释掉的
    ;;确认;;(打印retList)
    在输出
    ((C.2)(B.3))
    后达到退出条件
    (push(car listUnord)listRet)
    应将第三个元素
    (A.1)
    推到列表的前面并返回
    listRet
    。这与我设计其他具有输出的函数的方式是一致的,并且是有效的

    我错过了什么

    *编辑以下是我使用的两个帮助器函数:

    (defun remove-element (origPairList origPair)
      (let ((retlist (list)))
        (loop for pair in origPairList
          do (if (not(equal(car origPair)(car pair)))
               (push pair retlist)))
      retlist))
    
    (defun last-element-by-pair (pairList)
      (let ((lastEl (car (car pairList))))
        (if (not (null (cdr pairList)))
          (loop for el in pairList
             do (setf lastEl (car el))))
      lastEl))
    
    一些提示

    简化事情

    (defun remove-element (origPairList origPair)
      (let ((retlist (list)))
        (loop for pair in origPairList
          do (if (not(equal(car origPair)(car pair)))
               (push pair retlist)))
      retlist))
    

    糟糕的汽车/cdr混乱。在循环中使用分解结构。

    (loop for pair in foo ... (car pair) ... (cdr pair) ... (car pair) ...)
    

    不要一直走列表

    然后

    其他问题:

    您还需要确保代码正确缩进。通常是在编辑器中击键来完成此操作。另外,您的代码缺少右括号。因此,代码在语法上是不正确的

    (defun sort-by-freq (listUnord listOrdFreqs &optional startList)
      (print startList)
      (let ((listRet startList))
        (if (equal (length listUnord) 1)
            (push (car listUnord) listRet) ;; <- this makes no sense.
                                           ;; since you quit the function
                                           ;; there is no useful effect
          (loop for pair in listUnord
                do (if (and (equal (cdr pair) (car listOrdFreqs)) 
                            (not (equal (last-element-by-pair listUnord)(car pair) ))) 
                       (push pair listRet)
                     (if (and (equal (cdr pair) (car listOrdFreqs)) 
                              (equal (last-element-by-pair listUnord)(car pair)))
                         ;; this call to sort-by-freq makes no sense.
                         ;; you are not using the return value 
                         (sort-by-freq ;; what are you appending here, only one list?
                                       (append (list (cons (car pair) (cdr pair))
                                                     (remove-element listUnord pair)))
                                       listOrdFreqs
                                       listRet)
                       (if (equal (last-element-by-pair listUnord)(car pair))
                           ;; this call to sort-by-freq makes no sense.
                           ;; you are not using the return value 
                           (sort-by-freq (remove-element listUnord (car listRet))
                                         (cdr listOrdFreqs)
                                         listRet))))))
        listRet))
    
    调用函数没有意义,因为没有使用返回值。调用该函数的唯一原因是它是否有副作用

    例如:

    CL-USER 310 > (loop for e in '(1 2 3 4)
                        do (if (evenp e)
                               (* e 10)
                             (* e 100)))
    NIL
    
    如您所见,它返回零。可能不是你想要的。

    一些提示

    简化事情

    (defun remove-element (origPairList origPair)
      (let ((retlist (list)))
        (loop for pair in origPairList
          do (if (not(equal(car origPair)(car pair)))
               (push pair retlist)))
      retlist))
    

    糟糕的汽车/cdr混乱。在循环中使用分解结构。

    (loop for pair in foo ... (car pair) ... (cdr pair) ... (car pair) ...)
    

    不要一直走列表

    然后

    其他问题:

    您还需要确保代码正确缩进。通常是在编辑器中击键来完成此操作。另外,您的代码缺少右括号。因此,代码在语法上是不正确的

    (defun sort-by-freq (listUnord listOrdFreqs &optional startList)
      (print startList)
      (let ((listRet startList))
        (if (equal (length listUnord) 1)
            (push (car listUnord) listRet) ;; <- this makes no sense.
                                           ;; since you quit the function
                                           ;; there is no useful effect
          (loop for pair in listUnord
                do (if (and (equal (cdr pair) (car listOrdFreqs)) 
                            (not (equal (last-element-by-pair listUnord)(car pair) ))) 
                       (push pair listRet)
                     (if (and (equal (cdr pair) (car listOrdFreqs)) 
                              (equal (last-element-by-pair listUnord)(car pair)))
                         ;; this call to sort-by-freq makes no sense.
                         ;; you are not using the return value 
                         (sort-by-freq ;; what are you appending here, only one list?
                                       (append (list (cons (car pair) (cdr pair))
                                                     (remove-element listUnord pair)))
                                       listOrdFreqs
                                       listRet)
                       (if (equal (last-element-by-pair listUnord)(car pair))
                           ;; this call to sort-by-freq makes no sense.
                           ;; you are not using the return value 
                           (sort-by-freq (remove-element listUnord (car listRet))
                                         (cdr listOrdFreqs)
                                         listRet))))))
        listRet))
    
    调用函数没有意义,因为没有使用返回值。调用该函数的唯一原因是它是否有副作用

    例如:

    CL-USER 310 > (loop for e in '(1 2 3 4)
                        do (if (evenp e)
                               (* e 10)
                             (* e 100)))
    NIL
    
    如您所见,它返回零。可能不是你想要的。

    主要问题 您正在循环中的
    do
    子句中计算表达式。这个 返回的值永远不会在任何地方使用

    函数的返回值由局部变量
    listRet
    给出, 在函数的开头设置,并在 两个位置,对
    推送的两个调用。第一种情况只会发生在一段时间内
    输入大小为1的列表。第二次推送仅发生在步骤4

    我们不难看出,所有其他行动都没有任何效果 在本地
    listRet
    变量上。另外,由于
    也按频率排序
    因为您的辅助功能是纯的(它们从不破坏 列表结构由
    listRet
    指向),您还知道该列表是 不会通过不同的cons单元格链接进行修改 随着时间的推移

    让我们通过使用示例跟踪代码来确认这一点:

    (trace sort-by-freq last-element-by-pair remove-element)
    
    评估测试时,将发出以下跟踪(输出因实现而异,此处使用SBCL):

    这里可以看到的一个小问题是 使用相同的输入多次调用配对的最后一个元素 这是浪费。它可以在循环之前调用一次

    在0级,函数在对上迭代,直到找到
    (B.3)
    , 其频率等于第二个列表中的第一个频率。这是 步骤4,然后将该对推到 调用
    按频率排序时的局部变量
    listRet

    当循环到达无序列表的最后一个元素时 函数通过(i)无序对的新列表进行递归调用, 使用
    删除元素
    ,(ii)减少一次频率,以及(iii)当前
    列表绑定到
    listRet

    但是,无论在递归步骤中发生什么,特别是无论递归调用产生什么结果,绑定当前 在
    listRet的范围内
    将不再被修改。此外, str
    (loop for e in list
          do (compute-some-thing-and-return-it e))
    
    CL-USER 310 > (loop for e in '(1 2 3 4)
                        do (if (evenp e)
                               (* e 10)
                             (* e 100)))
    NIL
    
    (trace sort-by-freq last-element-by-pair remove-element)
    
    0: (SORT-BY-FREQ ((C . 2) (B . 3) (A . 1)) (3 2 1))
      1: (LAST-ELEMENT-BY-PAIR ((C . 2) (B . 3) (A . 1)))
      1: LAST-ELEMENT-BY-PAIR returned A
      1: (LAST-ELEMENT-BY-PAIR ((C . 2) (B . 3) (A . 1)))
      1: LAST-ELEMENT-BY-PAIR returned A
      1: (LAST-ELEMENT-BY-PAIR ((C . 2) (B . 3) (A . 1)))
      1: LAST-ELEMENT-BY-PAIR returned A
      1: (REMOVE-ELEMENT ((C . 2) (B . 3) (A . 1)) (B . 3))
      1: REMOVE-ELEMENT returned ((A . 1) (C . 2))
      1: (SORT-BY-FREQ ((A . 1) (C . 2)) (2 1) ((B . 3)))
    
        2: (LAST-ELEMENT-BY-PAIR ((A . 1) (C . 2)))
        2: LAST-ELEMENT-BY-PAIR returned C
        2: (LAST-ELEMENT-BY-PAIR ((A . 1) (C . 2)))
        2: LAST-ELEMENT-BY-PAIR returned C
        2: (LAST-ELEMENT-BY-PAIR ((A . 1) (C . 2)))
        2: LAST-ELEMENT-BY-PAIR returned C
        2: (REMOVE-ELEMENT ((A . 1) (C . 2)) (C . 2))
        2: REMOVE-ELEMENT returned ((A . 1))
        2: (SORT-BY-FREQ ((C . 2) (A . 1)) (2 1) ((B . 3)))
    
          3: (LAST-ELEMENT-BY-PAIR ((C . 2) (A . 1)))
          3: LAST-ELEMENT-BY-PAIR returned A
          3: (LAST-ELEMENT-BY-PAIR ((C . 2) (A . 1)))
          3: LAST-ELEMENT-BY-PAIR returned A
          3: (REMOVE-ELEMENT ((C . 2) (A . 1)) (C . 2))
          3: REMOVE-ELEMENT returned ((A . 1))
          3: (SORT-BY-FREQ ((A . 1)) (1) ((C . 2) (B . 3)))
    
          3: SORT-BY-FREQ returned ((A . 1) (C . 2) (B . 3))
        2: SORT-BY-FREQ returned ((C . 2) (B . 3))
      1: SORT-BY-FREQ returned ((B . 3))
    0: SORT-BY-FREQ returned ((B . 3))
    
    (defun sort-pairs-by-frequencies (pairs frequencies)
      ...)
    
     (if (and (equal (cdr pair) (car listOrdFreqs))
              (not (equal (last-element-by-pair listUnord)(car pair))))
         (push pair listRet) ;;step 4
         (if (and (equal (cdr pair) (car listOrdFreqs))
                  (equal (last-element-by-pair listUnord)(car pair)))
             (sort-by-freq (append (list (cons (car pair) (cdr pair)))
                                   (remove-element listUnord pair))
                           listOrdFreqs listRet) ;;step 6
             (if (equal (last-element-by-pair listUnord)(car pair))
                 (sort-by-freq (remove-element listUnord (car listRet))
                               (cdr listOrdFreqs)
                               listRet))))
    
    (if (and A (not B))
       (step-4)
       (if (and A B)
            (step-6)
            (if B (step-5))))
    
    (and b
         (not (and a b))
         (not (and a (not b))))
    
    => (and b
            (or (not a) (not b))
            (or (not a) b))
    
    => (and b (or (not a) nil) t)
    => (and b (not a))
    
    (cond
      (a (if b (step-6) (step-4)))
      (b (step-5)))
    
    (defun remove-frequency (pairs frequency)
      (remove frequency pairs :test #'= :key #'cdr))
    
    (defun keep-frequency (pairs frequency)
      (remove frequency pairs :test-not #'= :key #'cdr))
    
    (remove-frequency '((a . 20) (b . 10) (c . 5) (d . 20)) 20)
    => ((B . 10) (C . 5))
    
    (keep-frequency '((a . 20) (b . 10) (c . 5) (d . 20)) 20)
    => ((A . 20) (D . 20))
    
    (defun sort-pairs-by-frequencies (pairs frequencies)
      (if (null frequencies)
          pairs
          (destructuring-bind (frequency . frequencies) frequencies
            (append (keep-frequency pairs frequency)
                    (sort-pairs-by-frequencies (remove-frequency pairs frequency)
                                               frequencies)))))
    
    (sort-pairs-by-frequencies '((a . 20) (b . 10) (c . 5) (d . 20))
                               '(5 10 20))
    => ((C . 5) (B . 10) (A . 20) (D . 20))
    
     0: (SORT-PAIRS-BY-FREQUENCIES ((A . 20) (B . 10) (C . 5) (D . 20)) (5 10 20))
       1: (SORT-PAIRS-BY-FREQUENCIES ((A . 20) (B . 10) (D . 20)) (10 20))
         2: (SORT-PAIRS-BY-FREQUENCIES ((A . 20) (D . 20)) (20))
           3: (SORT-PAIRS-BY-FREQUENCIES NIL NIL)
           3: SORT-PAIRS-BY-FREQUENCIES returned NIL
         2: SORT-PAIRS-BY-FREQUENCIES returned ((A . 20) (D . 20))
       1: SORT-PAIRS-BY-FREQUENCIES returned ((B . 10) (A . 20) (D . 20))
     0: SORT-PAIRS-BY-FREQUENCIES returned ((C . 5) (B . 10) (A . 20) (D . 20))
    
    (defun sort-by-frequency (pairs frequencies)
      (let ((retList (list)))
            (loop for freq in frequencies
               do (push (extract-pair-match pairs freq (extract-keys retList)) retList))
        retList))
    
    (defun extract-pair-match(pairs match keys)
      (if (and (equal (cdr(car pairs)) match) (not (search-keys keys (car(car pairs)))))
            (car pairs)
            (extract-pair-match (cdr pairs) match keys)))
    
    (defun search-keys (keys match)
      (if (null keys)
          nil
          (if (equal (car keys) match)
          (car keys)
          (search-keys (cdr keys) match))))
    
    (defun extract-keys (pairList)
      (let ((retlist (list (car (car pairList)))))
           (loop for pair in (cdr pairList)
              do (push (car pair) retlist))
        retlist))
    
    (sort-by-frequency (list(cons 'c 2)(cons 'b 3)(cons 'a 1)) '(1 2 3))
    
    ((A . 1) (C . 2) (B . 3))