文档章节

【Scheme归纳】4 高阶函数

NoMasp
 NoMasp
发布于 2015/09/08 21:47
字数 1316
阅读 14
收藏 0

高阶函数的介绍

高阶函数的英文名称是Higher Order Function,它们是以函数为参数的函数。主要用于映射(mapping)、过滤(filtering)、归档(folding)和排序(sorting)表。高阶函数让程序更具模块性,让函数更加通用。

函数sort具有2个参数,一个是需要排序的表,另一个是定序(Ordering)函数。下面展示了按照大小将一个整数表正序排序。而<函数就是本例中函数的定序函数。

(sort(420 -130 138 983 0298 783 -783) <)
;Value:(-783 -130 0 138 298 420 783 983)

通过灵活使用定序函数,我们可以写出更强大的函数。

(sort(783 298 -289 429 892479 -197) (lambda(x y) (< (modulo x 100)(modulo y 100))))
;Value:(-197 -289 429 479 783 492 892 298)

我们之前讲过,modulo函数用来求余。

Scheme并不区别过程和其他的数据结构,因此你可以通过将函数当作参数传递轻松的定义自己的高阶函数。而且Scheme并没有定义块结构的语法,因此使用lambda表达式作为一个块。

映射

映射是将同样的行为应用于表所有元素的过程。R5RS定义了两个映射过程:其一为返回转化后的表的map过程,另一为注重副作用的for-each过程。

map过程的格式如下:

             (map procedurelist1 list2…)

procedure是个与某个过程或lambda表达式相绑定的符号。作为参数的表的个数视procedure需要的参数而定。

(map+(1 3 5)‘(2 4 6))
;Value:(3 7 11)
(map(lambda (x) (* x x))(1 2 3))
;Value:(1 4 9)

通过类比可以发现后者的lambda表达式相当于前者的+函数。只不过后者只有一个list,而前者有2个。如果想要像前者一样,让两个list中的元素一次相乘,除了用*外,也可以用lambda表达式。

(map(lambda (x y) (* x y))(1 2 3)(2 4 6))
;Value:(2 8 18) 

但是如果我们这样写:

(map (lambda (x) (* x x))(1 2 3)(1 3 5))

它并不会得出(1 4 9) (1 9 25)。

如果我们这样写:

(map (lambda (x y) (* x x) (* y y))(1 2 3)(1 3 5))

它得出的结果是(1 9 25),这是因为其只有一个返回值。但是(* x x)这一部分确实计算了。通过下面的例子我们可以确信这一点。

(map(lambda (x y) (let ((list1 (* x x)) (list2(* y y))) list1))(1 2 3)(1 3 5))
;Value:(1 4 9)
(map(lambda (x y) (let ((list1 (* xx)) (list2(* y y))) list1 list2))(1 2 3)(1 3 5))
;Value:(1 925) 这里同样是因为其只能有一个返回值。

而map函数最终的返回值以运算结果来判断。

(map - '(3 2 0) '(3 1 1 3))
;Value:(0 1 -1)
(map – '(3 2 0) '(3 1))
;Value:(0 1)

因为前者中list1中没有和list2中最后一个元素相对应的元素了,而后者中list2中没有和list1中最后一个元素相对应的元素。

(map(lambda (x y z) (* x x) (* y y) (* z z))(1 2)(3 4 5)(6 78 9))
;Value:(36 49)

而在这里例子中为什么最后的返回值不是(36 49 64 81),博主也不知道了,还请知道的网友留个回复。

for-each

for-each的格式与map一致,但是for-each并不返回一个具体的值,只是用于副作用。(副作用的解释)我们同样通过一个示例来展示。

(definesum 0)
;Value:sum
(for-each(lambda (x) (set! sum (+ sum x)))‘(1 2 3 4))
;Unspecifiedreturn value
sum
;Value:10

如前所述,for-each并没有返回值。

过滤

尽管过滤函数并没有在R5RS中定义,但MIT-Scheme实现提供了keep-matching-items和delete-matching-item两个函数。注意item后加和不加s。

(keep-matching-items(1 -2 3 -4 5)even?)
;Value: (-2 -4)

其中even?我们可以认为对应于上前文中sort函数的定序函数,当然,我们也可以用lambda来作为这个参数。

(keep-matching-items(10 39 0 -100 76)(lambda (x) (<= 10 x 100)))
;Value: (10 39 76)

归档

同样在R5RS中没有定义归档函数,但MIT-Scheme提供了reduce等函数。

(reduce + 0 '(1 2 34))                ;⇒ 10
(reduce + 0 '(12))                    ;⇒ 3
(reduce + 0'(1))                      ;⇒ 1
(reduce + 0'())                       ;⇒ 0
(reduce + 0'(foo))                    ;⇒ foo
(reduce list '() '(1 2 34))            ;⇒ (((1 2) 3) 4)
(define (sqrt-sum-sq ls) (sqrt (reduce + 0(map (lambda (x) (* xx)) ls))))

排序

同样在R5RS中没有定义排序函数,而在MIT-Scheme中提供了sort(实为merge-sort实现)和quick-sort函数。这个函数我们在前面展示过,下面我们用sort函数,lambda,tan函数和<来写一个以tan(x)的大小升序排列的函数。

(define(sort-tan ls) (sort ls(lambda (x y) (< (sin x) (siny)))))
;Value:sort-tan
(sort-tan(1 2 3 4 5 6))
;Value:(5 4 6 3 1 2)

apply函数

apply函数将一个过程应用于一个表,也就是将表展开作为过程的参数。该函数具有任意多个参数,但首末参数必须分别是一个过程和一个表。

(applymax(-1 2 -3))
;Value:2
(apply* 1 2(3 4 5))
;Value:120



感谢访问,希望对您有所帮助。 欢迎关注或收藏、评论或点赞。


为使本文得到斧正和提问,转载请注明出处:
http://blog.csdn.net/nomasp


版权声明:本文为 NoMasp柯于旺 原创文章,未经许可严禁转载!欢迎访问我的博客:http://blog.csdn.net/nomasp

本文转载自:http://blog.csdn.net/nomasp/article/details/44221039

NoMasp
粉丝 7
博文 334
码字总数 0
作品 0
镇江
程序员
私信 提问
加载中

评论(0)

编程语言--Scheme

Scheme语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来说,它并没有象 C++,java,C#那样受到商业领域的青睐,在国内更是鲜为人知。但它在...

匿名
2009/03/25
1.7W
1
nomasp 博客导读:Lisp/Emacs、Algorithm、Android

版权声明:转载请联系本人,感谢配合!本站地址:http://blog.csdn.net/nomasp https://blog.csdn.net/NoMasp/article/details/44966625 Profile Introduction to Blog 您能看到这篇博客导读...

nomasp
2015/09/17
0
0
Y Combinator学习总结

最近看完The little schemer,第一次看到这种编排的书,一问一答的形式,不知不觉就翻完了整本。很自然的教会大家写递归,怎样写程序,一点点的CPS,还有Y combinator。个人觉得第九章推导Y...

rongtou
2016/09/27
96
0
Common Lisp 和 Scheme 的函数命名空间不同

最近在 <> 看到 Common Lisp 和 Scheme 的不同: 1. 在Common Lisp眼中,一个符号的symbol-value和symbol-function是不一样的,而Scheme 对两者不作区分。在Scheme里面,变量只有唯一对应的值...

沙枣
2013/08/18
1.6K
4
如何提升JSON.stringify()的性能?

1. 熟悉的 在浏览器端或服务端,都是我们很常用的方法: 将 JSON object 存储到 localStorage 中; POST 请求中的 JSON body; 处理响应体中的 JSON 形式的数据; 甚至某些条件下,我们还会用...

AlienZHOU
2019/06/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

云端服务器迁移方案

场景描述 用于企业上云,提高服务器迁移时的系统还原度,降低操作难度,提高迁移速度。适用将物理服务器、虚拟机以及其他云平台云主机,一站式地迁移到阿里云 ECS,支持迁移主流 Windows 和 ...

阿里云官方博客
35分钟前
56
0
如何把灰大师Win10PE镜像安装到本地硬盘?(Win10PE硬盘版制作)

各位小伙伴,灰大师Win10PE维护系统,可以刻录成光盘引导,可以制作到U盘启动,可以用PXE或EFI PXE网启方式引导,这些引导方式均能愉快支持传统Legacy及新的UEFI模式。相关资源及教程,在本博客...

灰大师
37分钟前
57
0
Linux就该这么学 -- 命令 -- date

date命令用于显示及设置系统的时间或日期 格式:date [选项] [+指定的格式] date命令中的参数及作用 %t:跳格[Tab键] %Y:年(yyyy) %m:月(00~12) %d:日(00~31) %H:小时(00~24) %l...

jionzhao
50分钟前
56
0
1.4掌握日志工具的使用——Android第一行代码(第二版)笔记

Android中的日志工具类是Log(android.util.Log),这个类中提供了如下5个方法来供我们打印日志。 Log.v():用于打印那些最为琐碎的、意义最小的日志信息。对应级别verbose,是Android日志里面...

Cy23
55分钟前
57
0
System.currentTimeMillis和System.nanoTime

精度与 精确 我想知道的是在更新对象在游戏中的位置时应该使用System.currentTimeMillis()还是System.nanoTime() ? 他们的运动变化与自上次通话以来经过的时间成正比,我想尽可能地精确...

javail
今天
73
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部