您的位置:首页 > 编程语言 > C语言/C++

从 C++ 模板元编程生产质数看 F# 函数式编程思想

2009-08-10 19:59 411 查看
文 / 李博(光宇广贞)
话说 1994 年,C++ 标准委员会在圣迭哥举行的一次会议期间,Erwin Unruh 同学展示了一段可以产生质数的代码。这段代码的特别之处在于质数产生于编译期而非运行期,在编译器产生的一系列错误信息中间夹杂着从 2 到某个设定值之间 的所有质数。其改进版据说在 GCC 3.2 上得到验证。

源代码这里就不贴出来了,网上或者任一本《模板元编程(C++ Template Meta - Programming)》书里面都可以找得到。这里,我自己重写了一份,以便更简明地阐述本文的思想:

struct LB { LB ( void* ) { } };
// 迭代过程由递归代替循环计算
template < int n, int i > struct IsPrime
{enum{Prime=(n==2)||(n>1)&&(n%i)&&IsPrime<n,i-1>::Prime};};
// 特化,枚举特殊情况:递归结束条件
template < int n > struct IsPrime < n, 1 > { enum { Prime = 1 }; };
// 若 n 为质数,则将 1 赋给 lb 报错;若非质数,赋零给 lb 构造函数无恙
template < int n > struct PrimePrint
{
enum { Prime = IsPrime < n, n / 2 > :: Prime };
PrimePrint < n - 1 > p;
PrimePrint () { LB lb = Prime ? 1 : 0; }
};
// 全特化,处理递归结束条件
template <> struct PrimePrint < 1 > { };
#define LAST 10
int _tmain(int argc, _TCHAR* argv[])
{
PrimePrint < LAST > p;
return 0;
}


这段代码现在在 VS 2010 上已无法打印所有的质数,而只会打印离 LAST 最近的那个质数,这里是 7,到此便停止向深层递归,不知这算不算编译器学聪明了……若有哪位读者有其它的编译器可以做自我验证。

直观地验证质数的过程是迭代作除,若发现数 n 是 m ( 1 < m <= n / 2 ) 的倍数则 n 为非质数。迭代过程既可以用 for 循环来完成,也可以用函数递归来完成。显然,模板元编程是无法用 for、while、if 等运行时动作来循环判断的。判断唯一能用的就是三目算符 ?: 表达式。因此,迭代过程只能用递归来完成。递归终止条件使用特化模板描述。

这其实反应了函数式编程的思想——使用递归和模式匹配(Recursion & Pattern Matching)替代 for / wihle 和 if / else 以实现迭代和分支过程。在这一点上,二者思想是共通的。

话说,循环和分支是学习编程的重点。初学编程的同学对这两块没什么感觉。其实,循环和分支在提供着高效的程序流控制方案之外,隐含着极大的安全和性能隐患。for / while 循环的问题有增量控制,更有麻烦的边界检查;if / else 圈儿套泛滥对于 INTEL 系列处理器来说就是灾难。除了 C / ASM 之外,稍微高级点儿的语言都在这两块下了工夫。比如 C++ / C# 允许使用 foreach 代替 for 以免去增量控制和边界检查之烦;提倡 OOP 思想使用设计模式来尽可能消除 if / else 块,等等。但是治标不治本。

F# 做为一门优秀的函数式编程语言,尽管保留了 for 和 if 以适应程序员的旧习惯,却着重强调递归和模式匹配的程序设计思想解决这两块重点问题。相比较 C++ / C# 选择的 OOP 处理方案之不足,使用 F# 的这种设计思想写出来的代码优雅而严谨,尽显函数式程序设计的卓越之处

let IsPrime n =
let rec ExamPrime n i =
match n, i with
| 2, i -> true // 偏特化
| n, 1 -> true // 偏特化
| n, i when n < 2 || n % i = 0 -> false
| n, i -> ExamPrime n ( i - 1 )
ExamPrime n ( n / 2 )


C++ 模板元编程中的模板特化本身就是一种“模式匹配”思想的较为松散的体现,而在 F# 中,这种优秀的设计思想集中呈现出来,如代码中所注两行匹配,相当于 C++ 模板的偏特化处理。同样优秀的思想,在 F# 得以优雅而紧致地体现出来。这便是函数式编程的魅力所在。

另一篇模板元编程体现的 F# 函数式语言思想文章:由 C++ 模板元编程看 F# 对链表的处理

关于 F# 更多:我眼中的 F# 的前景和 C# 的失败F# 中的 LOP ——“面向语言编程”我眼中的微软大战略和中国软件之殇
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: