将列表转换为Racket中的独立实体?

时间:2016-07-23 02:49:58

标签: list racket

如何在不使用递归的情况下将数字列表转换为Racket中的单独实体?

例如,我想将(列出1 2 3 4)转换为单独的1 2 3 4数字,因此我可以将所有实体添加到一起,给我1 + 2 + 3 + 4 = 10。

4 个答案:

答案 0 :(得分:2)

“将列表分解为单独的实体”并没有真正使有那么多意义,因为这些数字必须存储在某处。编写定义时,将绑定到名称,如下所示:

(define x 7)

但是当你有一个列表时,你有多个值,所以为了将列表分成单个部分,你需要多个名字。如果您的列表长度始终相同,则这不是不可能的 - 您可以使用firstsecondthird等功能来提取单个值:

(define lst '(1 2 3))

(define a (first lst))
(define b (second lst))
(define c (third lst))

但是,列表通常不会以这种方式使用,并且在大多数情况下,列表可以是任意长度。因此,不可能知道提前给出值的名称,因为编写程序时所需的名称数量不一定是已知的!因此,您不希望“打破列表”,您 想要做的事情是立即对整个列表进行操作。

同时对整个列表进行操作的最原始的方法是显式使用递归,但大多数时候,有递归模式经常出现,有现有的函数要做没有编写所有样板的同样的事情。例如,map将函数应用于列表的每个元素,filter从列表中选择满足谓词的元素。但是,对于您的问题,您不需要这些内容:您希望一起收集列表的所有元素以生成单个值。

函数式编程中“收集元素”的概念称为 fold ,而Racket提供foldl(“左侧折叠”)函数来做到这一点。您提供了一个函数,在您的情况下+收集一个“零值”,它将用作起始累加器,以及要收集的列表。在这种情况下,“零值”只是数字0,因为零是附加标识:

(define (sum lst)
  (foldl + 0 lst))

> (sum '(1 2 3))
6

折叠是收集列表元素的一种非常通用的方式。但是,正如Alex Knauth提到的那样,Scheme为更简单的情况提供了另一种方法:因为S​​cheme中的+可以接受任意数量的参数,如果你提供两个以上的数字,它会隐式地进行折叠:< / p>

> (+ 1 2 3)
6

要使用一组参数作为列表而不是单独的值来调用函数,可以使用apply,它接受​​函数和列表作为参数:

(define (sum lst)
  (apply + lst))

这是在Scheme和Racket中执行数字列表的简单求和的惯用方法。

答案 1 :(得分:1)

你想要的是apply

> (apply + (list 1 2 3 4))
10

你有一个函数+,它接受​​多个参数(不是作为列表,而是作为单独的参数)。您希望将此函数应用于列表的元素,列表的每个元素都是要传入的单独参数。这正是apply的作用。

apply调用

(apply + (list 1 2 3 4))

相当于

(+ 1 2 3 4)

apply的主要优势在于它适用于计算列表,而不仅仅是硬编码的(list ...)表单,因此它也适用于append个列表:

> (apply + (append (list 1 2 3 4) (list 2 3 4)))
19

来自函数参数的列表,如Alexis King's answer所述:

> (define (sum lst)
    (apply + lst))
> (sum (list 1 2 3 4))
10
> (sum (append (list 1 2 3 4) (list 2 3 4)))
19

答案 2 :(得分:0)

将数字列表转换为它的独立实体。如果您知道长度可以使用访问者:

(define lst '(1 2 3 4))
(+ (first lst) (second lst) (third lst) (fourth lst)) ; ==> 10

firstsecond,...位于racket/list#!racket语言中。它们是更通用的cxr访问器的别名:

(+ (car lst) (cadr lst) (caddr lst) (cadddr lst)) ; ==> 10

如果你有一个列表lst,你知道它是合理的,少于200个元素,你可以使用apply将它们全部作为参数提供,甚至可以在前面提供额外的参数:

(apply + lst)   ; ==> 10
(apply + 5 lst) ; ==> 15

rest参数和apply之间存在对称性,因此有人可能将它们视为对话:

(define (prefix-zero . xs)
  (apply list 0 xs))

(prefix-zero 1 2 3) ; ==> (0 1 2 3) 

对于较大的列表,您可以使用foldl,将第二个参数作为中间值,使用两个和两个到一个值:

(foldl + 0 lst) ; ==> 10

foldl是使用递归实现的,它以+从0开始,每个元素都起作用:

(+ (cadddr lst) (+ (caddr lst) (+ (cadr lst) (+ 0 (car lst))))) ; ==> 10

答案 3 :(得分:-1)

我相信你也可能对quasiquote函数感兴趣。

用途更加通用,但是展示其运作方式的一个例子:

如果有列表,请说

(define list1 (list 5 6 7))

然后你可以创建另一个列表:

(define list2 `(1 2 3 4 ,@list1))
(define list3 `(1 2 3 4 ,list1))

(define list2 (quasiquote (1 2 3 4 (unquote-splicing list1))))
(define list3 (quasiquote (1 2 3 4 (unquote list1))))
> list2
'(1 2 3 4 5 6 7)
> list3
'(1 2 3 4 (5 6 7))