违反球拍合同(最大递归函数)

Racket Contract Violation (Max Recursion Function)

学习了一些Scheme/Racket,给点余地吧

目前正在尝试在不使用 built-in max() 函数的情况下找到给定列表的最大值。

当前代码:

#lang racket
(provide max-num)
(define (max-num lst)
  (define (helper lst max)
    (displayln lst)
    (displayln max)
    (displayln " ")
    (when (null? max) ; first run
        (helper (cdr lst) (car lst)))
    (if (null? lst)
        max ; then end
        (if (> (car lst) max) ; else compare
            (helper (cdr lst) (car lst)) ; then update max
            (helper (cdr lst) max)))) ; else keep max
  (if (null? lst)
      #f ; then Error
      (helper lst '())) ; else run helper
  )

(max-num '())
(max-num '(1 5 2 4 3))

通过 DrRacket 输出:

据我所知,displayln 输出告诉我我走在正确的轨道上。然而,它最终以违约告终?真的吗?错误而不是 returning 最大值。

我猜测 (if (null? lst)) 最后不想 return "max" 而是向 else 分支推进,尽管列表是空的。我环顾四周并调试了大约一个小时,现在无济于事。任何帮助将不胜感激。

你必须知道当你这样做时:

(when test
  do-something)
do-something-else

无论test是否正确,它总是do-something-else。所以发生的事情是第一轮 maxnull? 并且它 (helper (cdr lst) (car lst))) 并且 returns 是答案。然后它丢弃该答案并继续 if,其中 maxnull?,当 (> (car lst) max) 时它最终失败,因为 null? 不是数字。错误消息说它期望 real? 但它得到了初始值 '().

因此,为了提示您,除了本地定义外,您还应该有 一个表达式,例如。

(if test1
    result1
    (if test2
        result2
        alternative2))

(cond (test1 result1)
      (test2 result2)
      (else alternative2))

当然,因为您知道参数不是 null?,所以您可以调用 (helper (cdr lst) (car lst)) 而不是传递空列表并完全删除 whenwhenunless 是为了副作用而不是为了好的功能 Scheme 风格。