文档章节

我以为的函数式编程

leo-H
 leo-H
发布于 2015/01/07 01:14
字数 703
阅读 182
收藏 5

函数式编程

函数式编程(functional programming)的思想相对于命令式编程(imperative programming),告诉计算机你要什么而不是告诉它要怎么做,举个例子:

(defun fun(x)
   (list 'a (expt (car x) 2)))

这是函数是编程,而

(defun imp (x)
   (let* ((y (car x))
         (z (expt y 2)))
     (list 'a z)))
是命令式编程,结果一样,但思想不同。

函数式编程还要尽量避免对函数的参数进行修改,避免所谓副作用(side effect),除了某些地方要利用它的情况除外。
C语言只能返回一个值,所以有时候要用指针或引用传递参数作为返回值;而lisp可以返回多个值

由底向上

bottom-up programming相对于自上而下、分治的编程风格,优点:利用clisp交互式的编程环境,可以写完一个模块就马上进行测试;一些实用函数(utility function)还可以在今后的项目中使用,随着写的程序越多,这些实用函数就越显出价值,你的工具越丰富,程序就越简洁紧凑,磨刀不误砍柴工。

抽象

要写实用函数就需要培养抽象能力,发现相似程序共同的结构/pattern,比如经常要写类似这样的递归:
求类表的长度

(defun len(lst)
   (if (null lst)
       0
       (+ 1 (len (cdr lst)))))
判断列表lst中所有元素是否都被fn函数判断为真:
(defun all(fn lst)
   (if (null lst)
       t
       (and (funcall fn (car lst)) (all fn (cdr lst)))))

(其实clisp中以上这两个例子都已经有内置函数了,叫length和every)
它们结构相似,可以写一个更通用的函数来实现这种递归结构的函数的功能:

(defun rec(joiner end base)
   (labels ((inner-rec (lst)
      (if (null lst)
          (if (functionp end) (funcall end) end)
          (funcall joiner
                   (if (functionp base)(funcall base (car lst)) base)
                   (inner-rec (cdr lst))))))
      #'inner-rec))

定义的函数rec的返回值也是一个函数,这个返回的函数拥有递归的结构,可以实现上面len和all两个例子的功能:

(setf all2 (rec #'(lambda(x y)(and x y)) t #'oddp))
(funcall all2 '(1 2 3));相当于(all #'oddp '(1 2 3))

(setf len2 (rec #'+ 0 1))
(funcall len2 '(1 2 3));相当于(len '(1 2 3))

(setf copy (rec #'cons nil #'identity));生成一个用于复制列表的函数copy

(setf has-number (rec #'(lambda(x y)(or x y)) nil #'numberp));has-number判断列表是否含有数字

...

think recursively

作者在书中大量使用递归,尽管有时效率并不高,他认为递归让代码优雅。第一遍先用递归写,代码完成后再尽量改成尾递归,这样编译器(应该说是reader)会把尾递归优化成效率较高的迭代


© 著作权归作者所有

共有 人打赏支持
上一篇: 不拘一格的perl
下一篇: notes on python
leo-H
粉丝 23
博文 74
码字总数 28413
作品 0
厦门
私信 提问
听说有人没见过50岁以上的程序员

前同事在朋友圈里说没有见过50岁以上的程序员,我是见了不少。上个月学车的时候,见到一个和父亲年龄相仿的大学老师,严格说是大专的,教的是机械和机电自动化,聊起来发现,原来他是位资深的...

球球
2016/11/19
25
0
数论基础 扩展欧几里得 线性筛 逆元 欧拉函数 Lucas定理

扩展欧几里得 欧几里得算法,又叫辗转相除法,用于求两个数的最大公约数(gcd)。 由此可以得到最小公倍数 (先除防止溢出)。 扩展欧几里得,是用于解出方程 的一组解的。比如方程 ,可以解...

myjs999
2017/10/25
0
0
深入理解javascript中的立即执行函数(function(){…})()

javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花,当然,能理解各型各色的写法也是对javascript语言特性更进一步的深入理解。 ( function(){…...

hhj187
2016/09/29
4
0
如何学会 600 多种编程语言

几周前,做为8th Light公司的实习生,我从CEO那里拿到了我的工作成绩报告。在与CEO的会见期间,我发现了一个对如何做一个程序员的认识上的盲区。起初我以为,想扩展自己的软件职业道路,那就...

oschina
2013/03/20
8K
30
为什么我们要学习Haskell这样的编程语言

最近的几个月,我一直在学习一种叫Haskell的编程语言。由于里面有太多的从未遇到的编程概念,整个过程就像是完全重新学习如何编程。在i.TV网站上,我写了很多JavaScript(node.js和前端代码)...

红薯
2012/04/11
3.5K
12

没有更多内容

加载失败,请刷新页面

加载更多

大数据教程(13.6)sqoop使用教程

上一章节,介绍了sqoop数据迁移工具安装以及简单导入实例的相关知识;本篇博客,博主将继续为小伙伴们分享sqoop的使用。 一、sqoop数据导入 (1)、导入关系表到HIVE ./sqoop import --connect...

em_aaron
昨天
2
0
Git cherry-pick 使用总结

应用背景:假设现在有两个分支:dev_01, dev_02. 如果我想把dev_01分支上的某几个commit合并到dev_02分支, 那么怎么办呢? 这就是cherry-pick的工作了。cherry-pick会捡选某些commit, 即把某...

天王盖地虎626
昨天
9
0
css动态设置宽高

css 中可以使用 calc() 来动态设置宽高,但是,在表达式中运算符的前后必须要有空格 height:calc(100vh - 80px)

林梓阳
昨天
2
0
Git忽略提交规则 - .gitignore配置运维总结

在使用Git的过程中,我们喜欢有的文件比如日志,临时文件,编译的中间文件等不要提交到代码仓库,这时就要设置相应的忽略规则,来忽略这些文件的提交。简单来说一个场景:在你使用git add ....

二团长的迫击炮
昨天
7
0
记录一次用VB合并数据,确实很好用

Sub 合并()Dim row, col, val As DoubleFor row = 1 To 710 Step 1 For col = 1 To 15 Step 1 If IsNumeric(sheet2.Cells(row, col)) And IsNumeric(Sheet3.Cells(row, ......

蓝栩液枫
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部