1.3.2 使用LAMDBA 组合程序

1.3.2 使用LAMDBA 组合程序
在1.3.1部分中使用的SUM函数,似乎太麻烦了,为了在高阶函数中
作为参数使用,而不得不定义一些如PI-TERM之类的临时性的函数。
有更方便的直接使用的匿名方式来引用这些方法,而不是定义TERM。
我们能通过引入一个特定的符号,LAMDA来实现这一点。
LAMDA定义程序,使用LAMDA我们能够描述我们想要的如下:

 (lambda (x) (+ x 4))

 (lambda (x)  (/ 1.0 (* x (+ x 2))))
 然后 我们的程序pi-sum 能够在不用定义附加的程序的情况下表达成如下的样子:
 (define (pi-sum a b)
     (sum  (lambda (x)  (/ 1.0 (* x (+ x 2))))
            a
             (lambda (x) (+ x 4))
     b
      )
 )

再一次地使用lambda,我们能够写出程序integral 而不用定义附加的程序add-dx:
(define (integral f a b dx)
   (* (sum f
           (+ a (/ dx 2.0))
    (lambda (x) (+ x dx))
           b)
      dx
    )
)
总之,lambda被用来创建程序与define一样的方式,除了没有为程序指定程序名称:
(lambda (<formal-parameters>)  <body>)
lambda得到的程序与 define的程序一样的,仅有的区别是它没有关联到环境变量中的
任何一个名称。在事实上,
(define (plus4 x) (+ x 4))
等价于
(define plus4 (lambda (x) (+ x 4)  ))
我们能够如下的读一个lambda表达式:

(lambda (x) (+ x 4)  )
程序 有一个参数X 函数体是 X+4
像任何一个表达式一样,表达式作为一个程序有它自己的值。
一个lambda表达式能在一个表达式中作为一个操作符使用。例如:
((lambda (x y z) (+ x y (square z))) 1 2 3)
12

或者更通俗地说,我们可以任何地方像使用程序名一样地使用它。

使用LET创建局部变量
lambda的另一个用途是创建局部变量。在我们的程序中,我们常常需要局部变量,而不是
被绑定的形式参数。例如,我们要计算如下的函数公式。
f(x,y)=x(1+xy)^2+y(1-y)+(1+xy)(1-y)
我们也能表达为如下的式子:
a=1+xy
b=1-y
f(x,y)=xa^2+yb+ab
在写程序计算f时,我们想要包括的局部变量不仅有x,y 也有中间变量的名称a和 b
完成这个任务的一种方式是使用辅助的程序来绑定局部变量.
(define (f x y)
    (define (f-helper a b)
       (+ (* x (square a))
        (* y b)
  (* a b)))
    (f-helper (+ 1 (* x y)) (- 1 y))
 )
当然了,为了绑定我们的局部变量,我们能够使用一个lambda表达式来指定一个匿名的程序
程序F的程序体就成了对匿名程序的一个简单的调用.
(define (f x y)
     ((lambda (a b)
        (+ (* x (square a)) (* y b) (* a b))
      )
     (+ 1 (* x y))  (- 1 y)
     )
)
 这种结构太有用了,为此特别加了一个语法结构叫做LET,以使它使用起来更方便.
 使用LET,程序F,写出来如下:
(define (f x y)
    (let ( (a (+ 1 (* x y)))
           (b (-1 y))
  )
  (+ (* x (square a))
      (* y b)
      (* a b)
  )
     )
)
let表达式的通用格式如下:
(let ( (<var1> <exp1>)
       (<var2> <exp2>)
 .....
       (<varn> <expn>)
      )
    <body>
)

读作 在<BODY>中 让
变量1等于表达式1的值,
变量2等于表达式2的值,等等,
一直到N
变量N等于表达式N的值.
let表达式的第一部分是名称和表达式的数对的列表.
当let被执行时,任何一个变量名称都被赋于了相应的表达式的值.
let的程序体被执行时,这些名称被绑定为局部变量. let表达式的这种执行方式,与如下的语法是一致的.

((lambda (<var1> ...<varn>)
     <body>)
   <exp1> ....<expn>)
为了提供局部变量,在解释器中没有提供新的机制.LET表达式只是为了
使用LAMDBA表达式的一种简单的语法糖罢了。

从这种等价中,我们能够看到LET表达式中指定的变量的作用域是LET的程序体。看如下的实例:

让我们看一个变量绑定为局部变量的例子。例如,如果X等于5,下面的表达式的值是38。
(+ (let ((x 3))
    (+ x (* x 10))
    ) x)
在此,LET程序体中的X是3,LET表达式的值是33,外层的+程序的第二个参数X的值还是5。
变量的值被计算在LET的外面.当表达式需要为局部变量提供值时,它依赖于与局部变量同名的外部变量的值.例如,X的值是2,如下的表达式的值是12.

(let ((x 3) (y (+ x 2)))
    (* x y))
因为LET表达式的内部,X等于3,Y等于4,也就是外部的X加上2。

扫描二维码关注公众号,回复: 2565791 查看本文章

有时我们能够使用内部定义来达到和LET表达式一样的效果。例如我们能够定义上述的程序以如下的写法。
(define (f x y)
    (define a (+ 1 (* x y)))
    (define b (- 1 y))
    (+ (* x (square a)) (* y b) (* a b))
)

在这种情况下,我们优先使用LET。

练习1。34 假定我们定义程序
(define (f g) (g 2))
然后我们有如下的
(f square)
4

(f (lambda (z) (* z (+ z 1))))
6

当我们让解释器执行(f f)时,会发生什么情况呢?解释一下。

猜你喜欢

转载自blog.csdn.net/gggwfn1982/article/details/81412270
今日推荐