Common Lisp - 符号计算引论 第七章“Applicative Programming” 学习周记

    按照作者的说法,他准备介绍三种编程风格,首当其冲的就是本章了,本章的题目叫做Applicative Programming,直译叫“应用式编程”,网上查了,其实就是“函数式编程"的同义词,猜想Applicative Programming,想强调的是Applicative——高阶函数(high order function)用其他的函数和列表作为参数传入,并用这个传入的函数对列表进行计算然后得到一个结果。

一. 几个常用的built-in Common Lisp高阶函数

Common Lisp内建的几个高阶函数(书中叫Applicative Operator)有:

1. mapcar

    从函数名就能很好地理解它的作用,调用该函数需要传递函数和列表作为参数,然后该函数依次对列表中每个元素(顶层元素,不解析嵌套列表)调用该函数,然后将得到的结果集拼接成列表输出,所以叫map(映射),比如,对(1 2 3 4 5)每个元素求平方,如果用C语言写可能会是这样:

for (i = 0; i < sz; i++)
    result[i] = input[i] * input[i];

而Lisp写出来则是:

(mapcar #’(lambda(n) (* n n)) ’(1 2 3 4 5))

这里用了lambda表达式来编写一个平方函数,当然也可以另外定义一个square然后传递给mapcar,mapcar不是只能操作一个列表,实际上我们可以传递多个列表进去,而相应的函数就要变为多参数函数或多元运算符,(mapcar #'+ '(1 3 5 7 9) '(2 4 6 8 10))可以将两个列表对应相加的结果返回。

2. find-if

    参数为函数fn和列表lst,返回的结果为lst中第一个使fn为真的函数,可以带可选参数:from-end让find-if从后向前查找。

3. remove-if和remove-if-not

    传入的参数为函数fn和列表lst,remove-if将列表中所有使函数fn为真的元素删除,而remove-if-not将使函数fn为真的元素保留,其他的删除。

4. reduce

    归约函数,对一个列表进行操作,把列表中的元素用传入的函数参数进行计算,然后把计算得到的一个结果值返回,比如多个列表归并成一个:

(reduce #'append '(a b c) '(1 2 3) '(a a a))
得到 '(a b c 1 2 3 a a a)

5. every

    若传入的列表中每个元素都使参数函数fn为真,则every返回true,否则返回false

6. lambda表达式

    用途很多,其中的一个用途就是与高阶函数搭配使用,在调用上述高阶函数时,常常不用单独定义一个命名函数,而是在高阶函数参数传递中随手写一个lambda表达式,之后该表达式作为匿名函数参数传入高阶函数,完成所需要的计算,使用lambda表达式常常使得程序紧凑,易读。

7. “function”特殊函数

    若传递一个符号给该函数,则函数返回该符号代表的函数对象(Lisp中“符号”是一种数据类型,它可以表示某变量,可以表示某函数);若传递给它lambda表达式,则它返回该表达式对应的函数对象(词法闭包),一般用#'来表示,它使得函数在Lisp语言中成为“一等公民”——作为参数传递或作为结果返回。

(1)作为参数传递

    这种情况常见于各种高阶函数的调用中,如果需要自己实现一个高阶函数,也要用到它,如:

(defun rights (fn)
   (funcall fn '(life is like a battle)))
;调用(rights #'length)得到5
    这里要注意的是变量fn的值是一个函数,但它自己不是函数名,因此(fn '(life is like a battle))是错误的,必须用funcall来调用fn绑定的那个函数对象

(2)作为结果返回

    书上的例子,实现一个高阶函数,传入一个数字n,返回一个判断参数值是否大于n的谓词函数

(defun make-greater-than-predicate (n)
   #'(lambda (x) (> x n)))

该函数将返回一个谓词函数fn,fn接受一个参数x,并当x > n 时返回true,比如(make-greater-than-predicate 4)将返回一个谓词函数判断其参数是否大于4,那么

(find-if (make-greater-than-predicate 3) '(2 3 4 5 6 7 8 9))将返回第一个比3大的数4

8. trace和untrace工具

    trace可以用来跟踪函数的执行,但是要注意,跟踪内建函数有时候可能会导致死循环的发生。

最后,给出一段Lisp程序,该程序是本章的大练习,实现了一个简单的知识系统,该知识系统用数据库表示砖块的颜色,大小,形状和位置等信息,然后用一个简单的模式匹配器去试图从中获取知识,比如模式’(b1 ? b2)试图找出b1和b2的关系,'(b1 color ?)试图查找b1的颜色信息。

(defparameter *database*
  '((b1 shape brick)
    (b1 color green)
    (b1 size small)
    (b1 supported-by b2)
    (b1 supported-by b3)
    (b2 shape brick)
    (b2 color red)
    (b2 size small)
    (b2 supports b1)
    (b2 left-of b3)
    (b3 shape brick)
    (b3 color red)
    (b3 size small)
    (b3 supports b1)
    (b3 right-of b2)
    (b4 shape pyramid)
    (b4 color blue)
    (b4 size large)
    (b4 supported-by b5)
    (b5 shape cube)
    (b5 color green)
    (b5 size large)
    (b5 supports b4)
    (b6 shape brick)
    (b6 color purple)
    (b6 size large)))

(defun match-element (symbol1 symbol2)
  (or (equal symbol1 symbol2)
      (equal symbol2 '?)))

(defun match-triple (entry pattern)
  (every #'match-element entry pattern))

(defun fetch (pattern)
  (remove-if-not #'(lambda (entry)
		     (match-triple entry pattern))
		 *database*))

(defun color-pattern (block)
  (cons block '(color ?)))

(defun support-pattern (block)
  (append '(? supports) (list block)))

(defun supporters (block)
  (mapcar #'first (fetch (support-pattern block))))

(defun shape-pattern (block)
  (cons block '(shape ?)))

(defun supp-cube (block)
  (find-if #'(lambda (blk)
	       (find-if #'(lambda (entry)
			    (equal (third entry) 'cube))
			(fetch (shape-pattern blk))))
	   (supporters block)))

(defun description (block)
  (reduce #'append (desc2 block)))

(defun desc1 (block)
  (remove-if-not #'(lambda (entry)
		     (equal (first entry) block))
		 *database*))

(defun desc2 (block)
  (mapcar #'(lambda (entry)
	      (cdr entry))
	  (desc1 block)))

(defun description (block)
  (mapcar #'append (desc2 block)))


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值