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