Program Structure 笔记3 (高阶过程以及lambda语句)

Program Structure 笔记3 (高阶过程以及lambda语句)

  (作者:colinboy  Email:cybbh@163.com) 2008.5.2

(内容难免出现错误或一些专业词汇使用不当,只是个人笔记,能理解总体内容就好)

 

Generalize Patterns(程序设计中存在的通用模式)

 

(define pi 3.1415926)

(define (square-area r) (* r r))  //定义square-area函数

(define (circle-area r) (* pi r r))

(define (sphere-area r) (* 4 pi r r))

 

我们发现上面定义的函数形式参数都相同,功能都是某个数和r的平方相乘,那么我们可以把上面函数写成一个更通用的函数,例如:

(define (area shape r) (* shape r r))

(define square 1)

(define circle pi)

(define sphere (* 4 pi))

 

上面定义了一个area函数,通过参数shape传入要计算的图形

(area square 5) --> 25

上面的调用等同于 (square-area 5)

 

对于上面的一些计算面积的函数,我们通过发现它们运算性质的一些共性来写出了一个通用函数,但是对于很多应用,往往各种同类应用中的区别通过调用的函数不同而体现.

 

例如:

(define (sumsquare a b)
   
   
  (if (> a b)
   
   
      0
   
   
      (+ (* a a) (sumsquare (+ a 1) b)) ))
   
   

  
  
   
    
  
  
(define (sumcube a b)
   
   
  (if (> a b)
   
   
      0
   
   
      (+ (* a a a) (sumcube (+ a 1) b)) ))
   
   

  
  
   
    
  
  
(sumsquare 4 6) --> 77
   
   
对于(sumsquare 4 6)等于4*4 + 5*5 + 6*6, sumcube与此类似
    
    

  
  
   
    
  
  
我们如何写出一个通用函数sum,可以计算各种图形特定区间之内的面积和?
    
    

  
  
   
    
  
  
具体实现如下:
    
    
(define (sum fn a b)
   
   
   (if (> a b)
   
   
       0
   
   
   (+ (fn a) (sum fn (+ a 1) b))))
   
   

  
  
   
    
  
  
我们定义了一个sum过程,它需要3个参数才能工作,我们如何使用它??
    
    

  
  
   
    
  
  
首先我们需要定义2个求面积的函数
    
    
(define (square x) (* x x))
   
   
(define (cube x) (* x x x))
   
   

  
  
   
    
  
  
然后把定义的函数传入sum中就可以运行sum计算面积和了.
    
    
(sum square 4 6)  -->  77
   
   
(sum cube 4 6) -->  405
   
   

  
  
   
    
  
  
什么??  把一个函数当作参数? 
    
    

  
  
   
    
  
  
scheme,函数是一种类型,是一种值,我们可以把它当作参数传给其他函数!
    
    

  
  
   
    
  
  
一些例子:
    
    
(define (evens nums)
   
   
  (cond ((empty? nums) '())
   
   
        ((= (remainder (first nums) 2) 0)
   
   
         (se (first nums) (evens (bf nums))) )
   
   
        (else (evens (bf nums))) ))
   
   

  
  
   
    
  
  
(evens '(55 12 3 8 9 53))  -->  (12 8)
   
   
evens用来判定一组数中哪些数是否是偶数. evens使用了递归.
    
    

  
  
   
    
  
  
-------------------------------
   
   
(define (ewords sent)
   
   
  (cond ((empty? sent) '())
   
   
        ((member? 'e (first sent))
   
   
         (se (first sent) (ewords (bf sent))) )
   
   
        (else (ewords (bf sent))) ))
   
   

  
  
   
    
  
  
(ewords '(help what hi hell me you send))  -->  (help hell me send)
   
   
ewords用来检测一组单词中哪些单词中含有字母"e".
    
    

  
  
   
    
  
  
-------------------------------
   
   
(define (keep pred sent)
   
   
  (cond((empty? sent) '())
   
   
       ((pred (first sent))(se (first sent)(keep pred (bf sent))))
   
   
       (else (keep pred (bf sent)))))
   
   

  
  
   
    
  
  
(keep number? '(1 haha 88 go ok 3))  -->  (1 88 3)
   
   

  
  
   
    
  
  
keep2个参数,第一个参数为检测条件,第二个参数为要检测的数据,上面我们检测条件为number?(number?是一个原始内置函数), 那么keep函数会检查输入的一组数据中哪些是数字.
    
    
对于上面使用一个函数当作参数的函数我们成为高阶函数(Higher-Order Function)或者高阶过程(Higher-Order Procedure).
    
    

  
  
   
    
  
  
在数学领域中,经常讨论函数,例如
    
    
 f(x) = 2x + 6
   
   
上面定义了一个名为f的函数,我们会说函数f......等等内容,有时我们希望讨论一些没有名字的函数,我们通常会直接写出此函数的公式,例如
    
    
x |--> 2x + 6
   
   
|-->是一种映射.
    
    

  
  
   
    
  
  
scheme,对于上面2种函数的表示方法为:
    
    
对于f(x) = 2x + 6:
    
    
(define (f x) (+ (* 2 x) 6))
   
   

  
  
   
    
  
  
对于x |--> 2x + 6:
    
    
(lambda (x) (+ (* 2 x) 6))
   
   

  
  
   
    
  
  
lambda是定义一个没有名字的函数,它不和环境中的任何名字相关联.
    
    

  
  
   
    
  
  
对于前面定义的keep函数,我们可以使用如下方法调用:
    
    
(keep (lambda (wd) (equal? (first wd) (last wd))) '(
   
   
    
    california
   
    ese ope 
   
   
    
    alaska
   
   ))  --> (ese 
   
   
    
    
     
     alaska
    
    
   
   )
   
   
此调用的功能是对于输入的一组单词,检测出开头字母和结尾字母相同的单词.
    
    

  
  
   
    
  
  
define会返回一个函数名称!!
    
    
lambda会返回一个过程!!
    
    

  
  
   
    
  
  
(define (square x) (* x x))
   
   
(define square (lambda (x) (* x x)))
   
   

  
  
   
    
  
  
上面2个语句的作用是相同的,scheme,解释器会把第一个语句转换成第二个语句执行.
    
    

  
  
   
    
  
  
我们可以用lambda定义带有多个参数的过程,例如:
    
    
(define f (lambda (x y) (+ (* 2 x) y)))
   
   

  
  
   
    
  
  
(f 4 3)  -->  11
   
   
(f 5 6)  --> 16
   
   

  
  
   
    
  
  
lambda语句是一个特殊形式(special form).因为它不会计算所有实际参数表达式的值.
    
    

  
  
   
    
  
  
概念:
    
    
First class data
   
   
First class data在语言中可以当作:
    
    
1.一个变量的值
    
    
2.一个函数的参数
    
    
3.一个函数的返回值
    
    
4.一个集合的成员
    
    

  
  
   
    
  
  
例如对于大多数计算机语言,整数都是First class data,scheme,数字,(list),字符,过程等都是First class data.
    
    

  
  
   
    
  
  
((lambda (x) (* x x)) 5)  -->  25
   
   
上面的语句执行后会返回25,为什么??
    
    

  
  
   
    
  
  
前面我们讨论了如何把一个函数当作另一个函数的参数进行操作,那么如果一个函数的返回值为一个函数会怎么样呢?
    
    

  
  
   
    
  
  
1
    
    
(define (compose f g)
   
   
          (lambda (x) (f (g x))))
   
   
我们如何使用定义的compose函数呢?
    
    

  
  
   
    
  
  
(define second (compose first bf))
   
   
(second '(this is how to use))  --> is
   
   
我们定义了一个second函数,second会调用(compose first bf), compose会返回一个函数,所以second等同于:
    
    
(lambda (x) (first (bf x)))
   
   

  
  
   
    
  
  
(define (twice f) (compose f f))
   
   
(define third (twice square))
   
   
(third 5)  -->  625
   
   

  
  
   
    
  
  
对于上面的third函数,等同于(lambda (x) (square (square x)))
    
    

  
  
   
    
  
  
相比上面的例子,一个更简明的如何使用返回函数的函数例子:
    
    

  
  
   
    
  
  
(define (make-adder num)
   
   
          (lambda (x) (+ x sum)))
   
   
(define 3+ (make-adder 3))
   
   

  
  
   
    
  
  
(3+ 4)  -->  7
   
   
(3+ 1)  -->  4
   
   

  
  
   
    
  
  
注意:lambda会返回一个过程,这是理解上面例子的关键.
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值