0

关于循环的问题。

用列表做这件事总是让我感到困惑。你会怎么做这样的事情?

(define-struct song (title artist length))

(define song1 (make-song "Hey, Jude" "The Beatles" 431))
(define songs (list song
    (make-song "Sing" "JB" 200)
    (make-song "Yell" "LS" 188)))

(check-expect (count songs) 819)

计算所有歌曲的长度

(define (count n)
  (cond
    [(empty? n) 0]
    [else
   (first n)
(count (rest n)))

你会怎么做?使用结构,您可以简单地将它们分开。(+ (song-length)...不知道如何在列表中继续进行此操作。例如,我不确定什么是firstand restin songs1orsongs

4

2 回答 2

2

这个很简单,所以我不会破坏乐趣。事实上,你几乎明白了!使用此模板:

(define (count n)
  (cond
    [(empty? n) 0]
    [else
     (+ <???>
        (count (rest n)))]))

少了什么东西?只需询问列表中的当前歌曲(第一首歌曲),它的长度是多少。递归将负责将它们全部添加。

它与您用于迭代任何其他列表的模板相同:

  • 询问列表是否为空并返回适合这种情况的值。因为我们正在添加数字,所以返回0很好,它将很好地结束递归
  • 如果列表非空,只需从第一个元素(在本例中为歌曲的长度)获取感兴趣的值,其与递归调用(+再次使用 ,因为我们正在添加数字)组合并推进递归处理列表的其余部分
于 2013-11-14T02:07:31.963 回答
1

歌曲列表的每个元素都是一首歌曲。给定这样一个列表songs(car songs)是列表的第一个元素。 (song-length (car songs))返回列表中第一首歌曲的长度。看起来您正在尝试对所有歌曲的长度求和。习惯上,它可能或多或少看起来像这样:

(define (sum-lengths songs)
  (let sl ((songs songs)
           (sum 0))
    (if (null? songs) sum
      (sl (cdr songs) (+ sum (song-length (car songs)))))))

这种模式实际上只是计算一个fold. 你也可以写

(defun (sum-lengths songs)
  (foldl 0 (lambda (song sum) (+ sum (song-length song))) songs))

就个人而言,我认为您必须编写该lambda函数才能应用于song-length每首歌曲有点笨拙。你也可以做

(foldl 0 + (map song-length songs))

但这将建立一个中间列表来保存歌曲长度。我更喜欢 Common Lisp's reduce,其中您可以指定一个key应用于列表的每个元素的函数,您可以使用它编写:

(reduce '+ songs :key 'song-length)
于 2013-11-14T02:05:34.473 回答