函数应用——Applicative 编程

Table of Contents

Applicative 是函数式编程中的一个概念,通过函数应用来完成工作,例如,把函数对象传递给其他函数。

1. 匿名函数

通过 lambda 来定义,例如,定义一个匿名函数,将参数乘以 10:

(lambda (n) (* n 10))

变量 n 是闭包在匿名函数中的,因为这个性质,再加上函数可以作为参数和返回值,因此就能实现函数 Currying:

(defun print-log (level text)
  (format t "[~A] ~A~%" level text))

(defvar print-err (lambda (text) (print-log "ERR" text)))
(defvar print-info (lambda (text) (print-log "INFO" text)))
(defvar print-debug (lambda (text) (print-log "DEBUG" text)))
(funcall print-debug "debug...")

funcall 可以把传递的符号作为函数来调用。

2. map/mapcar/mapc

这几个函数都会将函数应用到一个或多个列表上。

mapcar:

(mapcar #'1+ '(1 2 3))                  ; => (2 3 4)
(mapcar #'+ '(1 2 3) '(4 5 6) '(2 2 2)) ; => (7 9 11)

mapc 则是没返回值的版本:

(mapcar (lambda (u) (format t "welcome: ~A~%" u)) '(user1 user2 user3))
;; 打印:
;; welcome: USER1
;; welcome: USER2
;; welcome: USER3

而 map 函数需要指定返回类型,如下,将字符列表中每个字母转成大写,最后返回字符串:

(map 'string #'char-upcase (list #\h #\e #\l #\l #\o)) ; => "HELLO"

3. reduce

(reduce #'+ '(1 2 3))                   ; => 6

4. remove-if/remove-if-not

对列表做一个“过滤操作”,在一些函数式编程语言中也被命名为“filter”。

remove-if 第一个参数是谓词函数,最后会删除返回为 T 的元素。例,过滤掉列表中的奇数:

(remove-if #'oddp '(1 2 3 4 5))         ; => (2 4)

remove-if-not 则相反:

(remove-if-not #'oddp '(1 2 3 4 5))         ; => (1 3 5)

5. find-if

传递一个谓词函数,返回第一个调用谓词函数结果为 T 的元素:

(find-if #'oddp '(2 4 6 7 8 9))         ; => 7

6. every/some

every:传递一个谓词函数,如果对列表中所有元素调用为 T,则返回 T:

(every #'plusp '(2 4 6 7 8 9))          ; => T,因为所有元素都大于 0
(every #'plusp '(2 4 6 7 8 9 0))        ; => NIL

some:只要其中一个为 T,就返回 T:

(some #'plusp '(-2 -1 0 1))             ; => T