【问题标题】:need practice using abstract list functions in scheme需要练习在方案中使用抽象列表函数
【发布时间】:2013-12-11 22:10:28
【问题描述】:

有没有人知道任何解释方案中抽象列表功能的好问题或网站?出于某种原因,我很难理解抽象列表函数以及如何使用它们。

当遇到一个只能使用抽象列表函数来解决的问题时,我几乎完全迷失了方向。

例如,我将如何编写一个仅使用抽象列表函数来查找列表中最大元素的函数?

这是我目前所拥有的:

(define (maximum lst)
  (foldr (lambda (e acc) (if (empty? acc) empty
                           (if (< acc e) acc empty))) empty lst))

有人可以向我解释为什么它不起作用以及我做错了什么吗? 非常感谢

【问题讨论】:

    标签: scheme


    【解决方案1】:

    (请注意,由于代码中foldr 的参数顺序,我假设您使用Racket;如果我对此有误,我可以将其调整为Scheme。)

    我愿意这样做:

    (define (maximum lst)
      (if (null? lst) 
          lst               
          (foldl 
           (lambda (e r) (if (< r e) e r))  ; function to call successively
           (car lst)                        ; initial value for the result r
           (cdr lst))))                     ; list to call function for (element by element)
    
    • 如果列表为空,则返回空列表(或任何您认为合适的;必要的,因为我们之后使用car,如果列表为空,则会抛出错误)
    • 如果没有,请使用foldl(为此,使用foldlfoldr 并不重要,但foldl 更有效)
      • 将结果初始化为第一个元素 (car)
      • 对于列表的其余部分 (cdr),使用 1. 下一个元素 2. 上一个结果调用函数
      • 在函数中
        • 如果 e > r,则返回 e,否则返回 r(返回值在下一次调用时绑定到 r,或者当每个项目都处理完后,将是 foldl 的结果)

    例子:

    (maximum '(3 6 7 1))
    
    1. r 初始化为 3 (car lst)
    2. 使用 e=6(下一个元素)和 r=3(初始化值)调用函数,返回 6
    3. 使用 e=7(下一个元素)和 r=6(上一个结果)调用函数,返回 7
    4. 使用 e=1(下一个元素)和 r=7(上一个结果)调用该函数,返回 7,因此 7 成为foldl 的结果

    注意,Racket 有第二种表达方式,可能更容易阅读,因为它更接近于传统的 for 循环:

    (define (maximum lst)
      (if (null? lst) 
          '()
          (for/fold ((r (car lst))) ((e (in-list (cdr lst))))
            (if (< r e) e r))))
    

    【讨论】:

      【解决方案2】:

      当您寻求帮助以了解它为什么不起作用时。

      (define (maximum lst)
        (foldr (lambda (e acc) (if (empty? acc) empty
                                 (if (< acc e) acc empty))) empty lst))
      

      这里的问题是您的初始对象是“空的”。这意味着accfold 的开头是空的。用英文你的代码会这样写:

      从空的开始折叠lst。如果acc 为空,则返回空。否则,如果acc 小于e,则返回e,否则返回空。返回值成为新的acc

      这里有两个问题:因为你从空开始:acc 总是空的。另一个问题在这里:

      (if (< acc e) acc empty)
      

      在这里,如果 acc 小于 e,您将返回 acc,否则您将返回空。但是如果acc 小于e 则意味着e 更大。这意味着您应该返回 e 而不是 empty

      没有真正的理由检查您的折叠中的empty?

      折叠调用如下所示:

      (foldr (lambda (e acc) (if (< acc e) e acc)) (car lst) (cdr lst))
      

      这意味着折叠列表其余部分的第一个元素。如果 acc 小于 e 则返回 e,否则返回 acc。返回值将在下一次迭代中替换 acc。

      您不需要做的就是检查空列表,您可能会得到类似的东西。

      (define (maximum lst)
        (if (empty? lst)
          (error "Cannot find max from empty list")
          (foldr
            (lambda (e acc)
              (if (< acc e) e acc))
            (car lst)
            lst)))
      

      还有一件事,foldlfoldr 是相同的,只是一个从第一个元素开始,一个从最后一个元素开始。在我的解决方案中,我没有测试过,但由于我的最后一个参数是整个列表,所以你使用哪个版本的 fold 无关紧要。

      【讨论】:

      • 'foldl' 是尾递归的,而 'foldr' 不是。 'foldl' 应该在可以使用的地方首选,
      • 这不是真的,即使一个从末尾开始(即 foldr)。这并不意味着它不是尾递归的。 (define (foldr func start lst) (foldl func start (reverse lst))) 它只是先做reverse 的事情。
      猜你喜欢
      • 2011-07-14
      • 2014-11-18
      • 2017-12-20
      • 1970-01-01
      • 1970-01-01
      • 2012-04-05
      • 2022-01-05
      • 1970-01-01
      • 2021-07-07
      相关资源
      最近更新 更多