免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5966 | 回复: 4
打印 上一主题 下一主题

什么是函数式编程? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-03-03 23:52 |只看该作者 |倒序浏览
转:yanmingcao
Wikipedia 对函数式编程的定义是:
Functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state.

函数式编程是一种编程范式,在这种编程方式中,我们更多的使用函数运算。函数运算的特点是没有状态和可变量,一个函数有输入值和输出值,运算一个函数不会产生任何副作用(side effect)。

与之相对的是Imperative Programming, 就是我们通常说的命令式编程。一般我们的编程方式都是命令式的,每一段程序都是指令,明确告诉计算机要做什么,运行指令的结果往往是程序状态(state)的改变。

一个例子最好说明两者的区别。让我们来打印八卦的符号。对程序员来说,这是一个很简单的作业。典型的程序会是这样的:


--------------------------------------------------------------------------------
view sourceprint?1 let yinyang = ['¦';'|']   

2     for x in yinyang do  

3         for y in yinyang do  

4             for z in yinyang do  

5                 printf "%c%c%c " z y x   

6   

7 Output:   

8   

9 ¦¦¦ |¦¦ ¦|¦ ||¦ ¦¦| |¦| ¦|| |||



--------------------------------------------------------------------------------

这里我用的是F#语言,一种函数式编程语言,但是它也可以用命令式的方式编程。我们用嵌套的for语句打印出每一爻,我们告诉计算机,第一爻有阴阳两种情况,第二爻有阴阳两种情况,第三爻有阴阳两种情况,循环后我们得到八种可能,然后打印结果。

这好像没有任何惊奇的东西。其实这里有一个很大的问题,这个问题就是,我们在编程之前就已经知道了结果!八卦是如何产生的?“太极生两仪,两仪生四象,四象生八卦,八卦生万物。”这个过程并没有在我们的程序中体现出来。世界的本质是变易,生生不息,周而复始。变易有其规律,比如牛顿万有引力定律,广义相对论,能量守恒定律等等。数学和物理学试图用函数的方式来描述这些规律,而我们的程序也可以以这种方式来编写。

下面是另一种方式来生成和打印八卦符号。


--------------------------------------------------------------------------------
view sourceprint?01 let generate a = a |> List.collect (fun x -> ['¦':; '|':])   

02   

03 [[]] |> generate   

04      |> generate   

05      |> generate   

06      |> List.map (List.fold (fun acc x -> acc + x.ToString()) ""   

07      |> List.iter (printf "%s "   

08   

09 Output:   

10   

11 ¦¦¦ |¦¦ ¦|¦ ||¦ ¦¦| |¦| ¦|| |||

--------------------------------------------------------------------------------

第一行定义了一个函数generate,它有一个输入值a,等号右边是函数的定义。关键部分是其中的一个变换函数:

        fun x -> ['¦':; '|':]

这个函数从每个输入值x生成了两个新的元素, 这两个新元素分别是由在x前面加上'¦'和'|'而生成的。

|> 是pipe-forward操作符(operator)。如果你熟悉Unix命令行,你对pipe应该很了解。它的作用就是将前面的值传送给后面的函数来处理。这其实是一种写法上的简化, 事实上|> 的定义是:

            let (|> x f = f x

|>的好处是可以将pipe连接起来用,程序看上去很直观,比如

        x |> f1 |> f2 |> f3

这相当于

        f3(f2(f1(x)))

回到上面的程序,第三行就是“太极生两仪”:

        [[]] |> generate

第四行是“两仪生四象”,第五行是“四象生八卦”。第六、七行是用来打印结果,在这里不是关键的。

这个例子中有一些语法和模块函数细节(比如List.collect, List.map),这里暂不做详细说明,这篇文章的目的是想说明函数式编程与命令式编程的区别。函数式编程有很明显的特征:

    1. 函数操作数据,函数没有副作用(side effect);
    2. 程序由一系列函数对数据的变换构成;
    3. 没有变量,只有输入值和输出值;

在第二个例子里面,我们从空([])生成了两仪,从两仪生成了四象,从四象生成了八卦,所有这些中间结果以及生成过程都在程序中体现出来。而在第一个例子里面没有。所以说函数式编程似乎更切合宇宙运行的本质,即变易的本质。

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
2 [报告]
发表于 2011-03-20 10:50 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
3 [报告]
发表于 2011-03-20 19:36 |只看该作者
Functional编程的意义何在?
pmerofc 发表于 2011-03-20 10:50



    不妨分成几个小问题:
  • 无副作用有什么意义?
  • lambda, 闭包有什么意义?
  • Curry 有什么意义?
  • 惰性求值有什么意义?
  • Monoid 有什么意义?
  • Monad 有什么意义?

论坛徽章:
0
4 [报告]
发表于 2011-03-21 09:01 |只看该作者
本帖最后由 KanonInD 于 2011-03-21 09:44 编辑

http://book.realworldhaskell.org/read/monads.html

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
5 [报告]
发表于 2011-03-21 12:28 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP