mult n 0 = 0
mult n m = (mult n (m – 1)) + n
-- 6
mult 3 2
--计算过程
mult 3 2
=> (mult 3 (2 - 1)) + 3
=> (mult 3 1) + 3
=> (mult 3 (1 - 1)) + 3 + 3
=> (mult 3 0) + 3 + 3
=> 0 + 3 + 3
=> 6
用C++ 11的模版元编程来写乘法:
template < int N1, int N2 >
class Mult {
static const int value = Mult<N1, N2 - 1>::value + N1;
};
template < int N1 >
class Mult <N1,0> { static const int value = 0; };
// 6
int result = Mult<3,2>::value;
//计算过程
Mult<3,2>::value
=> Mult<3,1>::value + 3
=> Mult<3,0>::value + 3 + 3
=> 0 + 3 + 3
=> 6
惰性求值
简单说,就是到需要的时候再计算,不需要的时候不必计算
优势是,节省计算时间,节省内存使用。还有可以和无限数据结构结合(infinite data structures)
title: C++11之函数式风格编程 date: 2017-03-3 10:48:40 tags:
函数式编程
函数式风格编程
自动类型推导,auto和decltype
lambda表达式的支持, 闭包,函数即数据
偏函数应用(partial funtion application),std::function和std::bind,lambda表达式和auto
STL与高阶函数的组合
用变参模版(variadic templates)来进行列表生成(List manipulation)
用模版全特化(full template specialisation)和偏特化(partial template specialisation)来进行模式匹配(pattern matching)
用std::async来进行惰性求值
为什么要以函数式风格来编程
STL结合lambda表达式更加简洁高效
模式匹配之模版元编程
还有更好更简洁的编程风格
什么是函数式编程
函数式编程就是以数学中的函数概念进行编程
数学中的函数在给定同样参数的情况下,每次调用函数的返回值都相同,不会有副作用(side-effect)
正因为函数调用没有副作用,那么函数从语义上相当于结果(Result),是等价的,可以互相替换
因为无副作用的特性,编译器的优化器可以从更高层次来优化,增加优化潜力,重新组合函数的调用顺序,或者把不同的函数调用放到不同的线程中并行计算,提高并发可能性
程序的控制流就是以数据依赖驱动的了,而不是指令顺序
函数式编程的特点
一等函数
其实C语言也有类似的特性,函数指针,这样就有更强的表现能力,也明面上支持了回调。C++ 11直接支持lambda表达式了。就不需要那么复杂和不安全的函数指针了。
一等函数表达能力之分发表(Dispatch Table)
高阶函数
说到这里,可能有人懵了,一等函数和高阶函数有啥不一样?请看以下代码块就知道了:
以上代码,函数make_add就是高阶函数,匿名函数function(a,b)可以被bind到变量f上,或者本身也可以直接返回,所以这匿名函数就是一等函数。
所以,高阶函数用朴素的观点来理解的话,可以这么说:高阶函数是一等函数的应用
很多函数式编程语言,有三种经典的高阶函数应用直接体现:
map , 应用一个函数到列表的每一个元素(element)上
filter, 从一个列表中移除一些元素
fold, 通过二分操作分解一个列表,直到一个列表变成单值(a single value)
很多编程语言已经有以上三种语义的支持了:
这三种语义有无数经典的应用场景:
Map + Reduce = MapReduce
Haskell
Python
C++ 11
纯函数
纯函数是独立的,这样让程序验证更加容易,也更加利于重构,测试,维护
非常有利于优化,比如,保存函数的调用结果,并行化
单子(Monad),是Haskell处理“不纯世界”的一种解决方案,它封装了不纯的世界,也是Haskell中的一个很重要的子系统,它也是表示计算的一种结构,甚至可以定义一组计算的组成结构
递归
C++ 11
同样的计算阶乘方式,我们用Haskell的模式匹配来实现以下:
列表处理
比如:[1,2,3,4,5] head(x) = [1] tail(xs) = [2,3,4,5]
那么用模式匹配+递归写出如下Haskell代码:
下面用C++ 11 的变参模版来做以上的求和:
其实呢,归而结网,列表处理的核心思想就是模式匹配。
再举个例子,用Haskell的模式匹配写一个乘法函数:
用C++ 11的模版元编程来写乘法:
惰性求值
优势是,节省计算时间,节省内存使用。还有可以和无限数据结构结合(infinite data structures)
EOF