我在计划之旅中遇到了另一个障碍。可以肯定地说我的桌子已经足够我敲我的脑袋......我已经写了一个函数来找到课堂作业列表中的最小和最大数字。逻辑是合理的(我认为是......)并且一切正常,但是,只有(define(迭代器aList minNum maxNum))返回第一个函数调用的值。我在调试器中注意到的是,在每次递归/函数调用之后,我看到(使用DrRacket)函数调用被推送到堆栈。一旦递归发生最后一次并且代码跳转到(list minNum maxNum)的返回,它就不会返回它应该的内容,因为我可以看到值是正确的,而是我看到函数调用从堆栈中移出一个接一个,直到它到达第一个。因此,返回将形成列表的前两个值的初始值。我知道堆栈是FIFO,但是,我甚至都没有尝试将任何东西推到堆栈中。从理论上讲,我只想再次调用该函数并继续传递值...对此的任何指导都将非常感激。
(define (findMinMax aList)
(define (iterator aList minNum maxNum)
(when(not(null? aList))
(cond
((> minNum (car aList))
(set! minNum (car aList)))
((< maxNum (car aList))
(set! maxNum (car aList))))
(iterator (cdr aList) minNum maxNum))
(list minNum maxNum))
(cond ; setting the first two atoms in a list appropriately to the min and max variables.
((< (car aList) (car(cdr aList)))
(iterator (cdr (cdr aList)) (car aList) (car(cdr aList))))
((> (car aList) (car(cdr aList)))
(iterator (cdr (cdr aList)) (car(cdr aList)) (car aList)))
(else
(iterator (cdr (cdr aList)) (car aList) (car(cdr aList))))))
答案 0 :(得分:2)
您需要重写代码,不要使用set!
或when
,因为它会让您重新学习计划。在使用Lisp方言而不是使用Algol方言时,你必须要有不同的思维方式,所以尽量只在递归中进行更改,而不是使用set!
并使用3方式if
而只是在一个表达式中使用过程
(define (my-length lst)
(define (length-aux lst n)
(if (null? lst)
n ; base case, return the length
(length-aux (cdr lst) (+ n 1)))) ; instead of set! we put the new value as argument
(length-aux lst 0)) ; one expression that calls the auxiliary procedure to do the calculations
您的内部程序可以简单:
(define (iterator aList minNum maxNum)
(if (null? <???>)
(list minNum maxNum)
(iterator <???>
(min <???> <???>)
(max <???> <???>))))
或者使用if
代替min
/ max
(define (iterator aList minNum maxNum)
(if (null? <???>)
(list minNum maxNum)
(let ((n (car aList))) ; use n to compare with minNum/maxNum
(iterator <???>
(if <???> <???> <???>)
(if <???> <???> <???>))))
答案 1 :(得分:2)
你对Scheme的复杂程度已经比大多数人好了!有一个非常有用的Scheme语法关键字&#39; named-let&#39;这使得定义内部递归函数定义变得容易。这是一个将您带到下一个级别的示例:
(define (findMinMax list)
(assert (not (null? list)))
(let finding ((list (cdr list))
(lMin (car list))
(lMax (car list)))
(if (null? list)
(values lMin lMax)
(finding (cdr list)
(min lMin (car list))
(max lMax (car list))))))
另请注意,我已使用values
句法形式返回两个值。而且,我使用了内置函数min
和max
。此外,finding
的使用是尾递归的,这意味着Scheme编译器将此递归调用转换为迭代调用,因此不需要堆栈帧。
答案 2 :(得分:1)
你有一些误导性的缩进。缩进步骤1确实不可取。 2你可以,但是当你学习Scheme时,4会更好。
实际上,您只需要在语法方面进行一些最小的更改。而不是
(define (findMinMax aList)
(define (iterator aList minNum maxNum)
(when (not (null? aList))
(cond
((> minNum (car aList)) ; change the local
(set! minNum (car aList))) ; variable's value
((< maxNum (car aList))
(set! maxNum (car aList))))
(iterator (cdr aList) minNum maxNum)) ; pass new values on, but
; ignore recursive result, and
(list minNum maxNum)) ; return the current values instead!
你需要:
(define (findMinMax aList)
(define (iterator aList minNum maxNum)
(if (not (null? aList))
(begin
(cond
((> minNum (car aList))
(set! minNum (car aList)))
((< maxNum (car aList))
(set! maxNum (car aList))))
(iterator (cdr aList) minNum maxNum)) ; return recursive result!
(list minNum maxNum))) ; ELSE - base case
初始通话只是:
(iterator (cdr aList) (car aList) (car aList)))
答案 3 :(得分:0)
是的,远离集合!或者你不会学习计划的功能方面的绳索。如果某些事情非常混乱,你可以使用它但是很少见到这种情况。
这里的很多答案用递归表示,但通常更容易理解的是高阶函数
内置的最小值和最大值都在某些实现中以折叠方式定义。
(define (min first . L) (fold (lambda (x y) (if (< x y) x y)) first L))
(define (max first . L) (fold (lambda (x y) (if (> x y) x y)) first L))
(define (MinMax first . L)
(define (internal y x)
(let ((min (car x))
(max (cdr x)))
(cons (if (< min y) min y)
(if (> max y) max y))))
(fold internal (cons first first) L))
请注意,当您可以将您的操作与更高阶函数相符时,代码的清晰程度。两行定义ADT,两行表示折叠如何携带本地状态,一行表示实际过程。
;;示例通话
> (minmax 0 9 3 4 7 6 -2)
;Value 4: (-2 . 9)