到底什么是函数式编程思维
2个回答
展开全部
形而上的思维:
1、数据不可变的思维:let a = 100,意义不是把100赋值给变量a,而是把a符号绑定(或者叫匹配)到100。
2、一切皆表达式思维:if b then 100 else 10,这不是条件跳转,而是一个三元表达式。
3、函数是第一类值:函数可以作为参数传输,也可以作为结果返回,更可以由一个函数演化成另一个函数。
形而下的思维:
1、用递归替换循环。
2、难以尾递归的时候考虑使用延续函数(continuation)。
3、高阶函数、部分应用、Lambda演算。
4、用泛型、接口、可区别联合类型替换类继承。
5、用二叉树替换普通链表后可以支持高并发计算。
===================================================
这些也只是feature而不是思维。我想知道的是这些feature之后的逻辑。
-----------------------------------------------------------------------------------------------------
再往上说就不接地气了,先从函数式语言说起,函数式语言其实就是模仿人的数学思维而发明的朴素,后来因为离机器太远,不容易优化而被诟病。但科技发展到今天,编译器的优化能力已经很强,软件系统越来越复杂,人的分工越来越细,函数式语言离数学更近,离机器更远,反而成为一种优势,有助于人把问题清晰化。从这个层面看,函数式编程是一种什么思维,就是推离机器的数学思维。这里没有内存、寄存器的想法,在 a=1之后,a 就不可能再等于2,当然你可以在 let a = 1 之后,再 let a = 2,但是这个a 就已经不是那个a,在停留在有内存概念的编程世界里,a 一直是 a,它是装东西的桶或者盒子,只是每次里面装的东西不同。
那么,总的来说,是先有朴素的函数式语言,然后才有今天发现函数式编程的好处, 启用了函数式语言的某些 feature,目的是为了把问题解构成更小的粒度。所以这些feature背后没什么逻辑,就好像问这石头为什么长这样一样。我只能打句偈语:本来就这样。
1、数据不可变的思维:let a = 100,意义不是把100赋值给变量a,而是把a符号绑定(或者叫匹配)到100。
2、一切皆表达式思维:if b then 100 else 10,这不是条件跳转,而是一个三元表达式。
3、函数是第一类值:函数可以作为参数传输,也可以作为结果返回,更可以由一个函数演化成另一个函数。
形而下的思维:
1、用递归替换循环。
2、难以尾递归的时候考虑使用延续函数(continuation)。
3、高阶函数、部分应用、Lambda演算。
4、用泛型、接口、可区别联合类型替换类继承。
5、用二叉树替换普通链表后可以支持高并发计算。
===================================================
这些也只是feature而不是思维。我想知道的是这些feature之后的逻辑。
-----------------------------------------------------------------------------------------------------
再往上说就不接地气了,先从函数式语言说起,函数式语言其实就是模仿人的数学思维而发明的朴素,后来因为离机器太远,不容易优化而被诟病。但科技发展到今天,编译器的优化能力已经很强,软件系统越来越复杂,人的分工越来越细,函数式语言离数学更近,离机器更远,反而成为一种优势,有助于人把问题清晰化。从这个层面看,函数式编程是一种什么思维,就是推离机器的数学思维。这里没有内存、寄存器的想法,在 a=1之后,a 就不可能再等于2,当然你可以在 let a = 1 之后,再 let a = 2,但是这个a 就已经不是那个a,在停留在有内存概念的编程世界里,a 一直是 a,它是装东西的桶或者盒子,只是每次里面装的东西不同。
那么,总的来说,是先有朴素的函数式语言,然后才有今天发现函数式编程的好处, 启用了函数式语言的某些 feature,目的是为了把问题解构成更小的粒度。所以这些feature背后没什么逻辑,就好像问这石头为什么长这样一样。我只能打句偈语:本来就这样。
展开全部
试着把函数想象成一个根据一个指定输入产出指定输出的黑盒,就能简化成逻辑电路中的各种门的样子或者是各种流通管道的样子。
然后试想数据通过这些组合起来的管道/门,变成你要的结果。
或者是通过现有的管道或门,构建(抽象)出更复杂/更通用的管道/门。
这就是函数式编程。
任何支持函数的语言都可以进行函数式风格的编程 注意到与命令式风格不同的是没有赋值,这意味着reason 程序的时候每个变量的值是不变的 不用考虑程序变量随着时间的变化 -- 大大降低了程序的复杂性。
既然C/C++(98) 也能进行函数式风格的编程 为什么不认为它是一门函数式语言呢,因为需要容易的进行函数式编程需要以下几个语言特性支持
1. closure
按照上面的三条规则函数式是first class 的 是可以直接传递作为参数的,而因为lambda演算作用于是lexical scope 的,variable capture 意味着语言要支持GC才能更方便的操作。 这意味着像Java(8以前), C/C++ 这两门工业界语言函数式编程并不非常适合.
2. 高阶类型推断
因为函数可以作为参数,其类型可以非常复杂 比如下面的函数类型其实非常普遍:
val callCC : (('a -> 'b -> 'c) -> ('a -> 'c) -> 'd) -> ('a -> 'c) -> 'd
如果没有类型推断,其实很难写对或者理解它的语义
3. tail-call
因为函数式风格没有赋值,也就没有for循环, 要实现循环操作 只能通过递归调用, 比如下面简单的例子:
let rec even n = if n = 0 then true else if n = 1 then false else odd (n - 1)
and odd n = if n = 1 then true else if n = 0 then false else even (n - 1)
这需要编译器保证上面的例子不能有stackoverflow 能提供这样保证的编译器并不多,比如所谓的 "函数式" 语言scala 就不能提供这种保证 也就实际上不是函数式语言.
相比函数式风格我觉得更重要的一个语言特性的时代数数据类型和模式匹配
然后试想数据通过这些组合起来的管道/门,变成你要的结果。
或者是通过现有的管道或门,构建(抽象)出更复杂/更通用的管道/门。
这就是函数式编程。
任何支持函数的语言都可以进行函数式风格的编程 注意到与命令式风格不同的是没有赋值,这意味着reason 程序的时候每个变量的值是不变的 不用考虑程序变量随着时间的变化 -- 大大降低了程序的复杂性。
既然C/C++(98) 也能进行函数式风格的编程 为什么不认为它是一门函数式语言呢,因为需要容易的进行函数式编程需要以下几个语言特性支持
1. closure
按照上面的三条规则函数式是first class 的 是可以直接传递作为参数的,而因为lambda演算作用于是lexical scope 的,variable capture 意味着语言要支持GC才能更方便的操作。 这意味着像Java(8以前), C/C++ 这两门工业界语言函数式编程并不非常适合.
2. 高阶类型推断
因为函数可以作为参数,其类型可以非常复杂 比如下面的函数类型其实非常普遍:
val callCC : (('a -> 'b -> 'c) -> ('a -> 'c) -> 'd) -> ('a -> 'c) -> 'd
如果没有类型推断,其实很难写对或者理解它的语义
3. tail-call
因为函数式风格没有赋值,也就没有for循环, 要实现循环操作 只能通过递归调用, 比如下面简单的例子:
let rec even n = if n = 0 then true else if n = 1 then false else odd (n - 1)
and odd n = if n = 1 then true else if n = 0 then false else even (n - 1)
这需要编译器保证上面的例子不能有stackoverflow 能提供这样保证的编译器并不多,比如所谓的 "函数式" 语言scala 就不能提供这种保证 也就实际上不是函数式语言.
相比函数式风格我觉得更重要的一个语言特性的时代数数据类型和模式匹配
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询