假设有这样一个需求,我们需要对列表里面的每个数字都加倍,一种可能的操作是使用car cdr遍历递归,但是Scheme还提供了map这个内置函数,能够简洁快捷的实现。
先来看看这个函数:
1 | > (map + '(1 2) '(3 4) '(5 6)) |
map的作用就是遍历每一个列表,然后用第一个参数来对它们进行求值。比如上例,后续的参数是长度为2的列表,那么结果也是一个长度为2的列表,第一项就是把后面每个列表的第一项拿出来,使用+来就行求值,得到了9,类似的,第二项是12。
为了使数字加倍,我们需要定义一个double函数:
1 | (define (double x) (* x 2)) |
使用map和double得到我们的目的:
1 | > (map double '(1 2 3)) |
再介绍两个内置函数apply和eval,关键字就表示出它们的作用:
1 | > (apply + '(1 2 3)) |
来个简单的示例看看它们的应用:
1 | (define (average num-list) |
从上面几个例子,我们可以看出,使用apply map使得(至少看起来是的)所有元素平等的共同参与运算,而且,比使用car cdr递归更加直观,简洁。
那什么时候用eval,按照js经验,可能会有不能用apply的时候,比如define or and这些时候,就只能用eval了。
最后,我们看一个稍微复杂的例子。实现内置函数flatten:
flatten作用使得列表里面的元素展开,使之平级,都是最外层列表的元素。比如((1 2) 3)flatten之后就是(1 2 3)。
思路是,如果seq(传入的列表)不是一个列表,就返回一个空列表;否则,我们使用map函数,对seq中的每一个子列表进行flatten操作,最后,使用append把这些结果连接起来。
1 | (define (my-flatten seq) |
最后这个例子稍稍复杂了点,综合应用了apply map和递归的思想。