【问题标题】:Racket - output content of a listRacket - 列表的输出内容
【发布时间】:2011-12-26 22:21:26
【问题描述】:

我已经定义了一个列表(在 Racket/Scheme 中):

(define myList (cons 'data1 (cons 'data2 (cons 'data3 (cons 'data4 empty)))))

(list 'data1 'data2 'data3 'data4)

我想写一个函数循环遍历列表并输出列表的所有值。

(define (outputListData list)
  (cond 
    [(null? list) list]
    [else (getListData)]))

我可以通过什么功能循环浏览列表的内容?我知道可以使用first & rest 来获取列表数据,但我想这不是正确的方法。

顺便说一句:有没有像php.net 这样的好、紧凑的球拍参考?我发现 Racket 的官方文档非常令人困惑......

【问题讨论】:

  • 您对 Racket 文档有什么困惑?你看过docs.racket-lang.org/guide 的球拍指南吗?是比较温和的介绍。如果您仍然不确定递归,您可能还想查看如何设计程序,这是免费的在线htdp.org

标签: list recursion lisp scheme racket


【解决方案1】:

您可以使用 for 循环。示例:

(for ([x (list 1 2 3)])
    (printf "~s -> ~s\n" x (* x x)))

当然,还有更多功能性的方法可以做到这一点,但这种方法也有效。您可能需要查看如何设计程序之类的教科书来执行递归方法。见:http://www.ccs.neu.edu/home/matthias/HtDP2e/

【讨论】:

  • + 1 也是很好的答案,但我个人更喜欢 Jon 0 的答案。顺便说一句,非常有用的链接,非常感谢!
  • 这是迄今为止最好的答案,恕我直言。
【解决方案2】:

dyoo 的解决方案在像 Racket 这样内置有用的迭代例程的方案中非常简洁明了。不过,仅供参考,您的“outputListData”与标准递归方式相距不远。您只需要更改几行:

(define (outputListData list)
  (cond 
    [(null? list) #f]             ; actually doesn't really matter what we return
    [else (printf "~s\n" (first list))    ; display the first item ...
          (outputListData (rest list))])) ; and start over with the rest

由于这是一种并非旨在返回值的“命令式”过程,所以只要我们停止重复(以避免无限循环),我们对空列表做什么并不重要。如果列表不为空,我们会输出第一个元素并递归地从列表的其余部分开始。

顺便说一句,如果您只需要在其他函数中间使用“for”循环,那么您可以编写几乎相同的另一种方法:

(let loop ((l (list 'foo 'bar 'baz 'quux))) ; or put whatever input you need
   (cond ((null? l) #f)
         (else
           (printf "~s\n" (first l))
           (loop (rest l)))))

考虑这个“命名的 let”的一种方式是,它定义了一个名为 loop 的临时函数,其工作方式与上面的 outputListData 类似。 Scheme 有一个很好的特性,它不会为像这样的“尾调用”增加堆栈,所以你总是可以用这种递归风格编写“迭代”forwhile 循环。

我强烈推荐 Friedman 和 Felleisen 的 The Little Schemer 快速介绍这种函数编写风格!我是通过 Douglas Crockford 的页面 here 找到的。

【讨论】:

    【解决方案3】:

    根据 cmets 进行编辑:使用 for-each

    (for-each display myList)
    

    试试这个:

    (void (map display myList))
    

    分解:

    • (void x) 导致 x 被忽略,而不是作为值返回给 REPL/父表达式。
    • (map function lst):对于列表'(a1 a2 ... an),返回列表'((function a1) (function a2) ... (function an))

    所以我们使用 map 来显示所有的项目,但是由于我们只关心副作用而不关心返回值,所以我们在返回的列表上调用 void。

    官方文档:

    【讨论】:

    • 在不使用返回值时使用for-each,而不是map。作为奖励,您可以取消 void
    【解决方案4】:

    我认为最容易理解的解决方案是提出一个所谓的“list-eater”功能。这就是我的大学在 Racket 中引入递归和列表的方式。大多数关于球拍的书籍(即“如何设计程序”或“球拍领域”)也是这样解释的。这是代码:

    (define my-list (list 'data1 'data2 'data3 'data4)) 
    
    (define (print-list a-list-of-data)
      (when (not (empty? a-list-of-data))
        (print (first a-list-of-data))
        (print-list (rest a-list-of-data))))
    

    如果您使用示例列表my-list调用该函数,您将获得以下输出:

    (print-list my-list)
    
    'data1'data2'data3'data4
    

    该函数执行以下操作:只要给定列表不为空,它就会获取该列表的第一个元素并将其传递给函数print。然后,它告诉自己对列表的其余部分执行完全相同的操作。 (它在列表的其余部分调用自己。)第二部分就是他们所说的递归。

    但是,您可以使用名为 map 的函数来缩短它:

    (define (print-list a-list-of-data)
      (map print a-list-of-data))
    

    这基本上表示您希望在给定列表的每个元素上调用函数 print。输出完全一样。

    希望对您有所帮助!

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-25
    • 1970-01-01
    • 2021-02-01
    相关资源
    最近更新 更多