在此之前先说一些概念:
计算机最重要的两个元件:CPU(控制器、运算器)、存储设备(寄存器、缓存、内存、硬盘)。
算法需要实现,所以有了CPU,CPU需要运行算法,所以有了指令集、程序段,高级语言编写函数代替编写程序段。
算法运行需要数据支撑,且算法本身需要存储起来,所以有了 存储设备,存储设备可以永久存储数据,程序编写中变量就是数据。永久存储速度太慢,所以有了缓存设备和存储器体系。
冯诺依曼最杰出的思想就是:把算法记录成指令,当做数据存放,于是算法和数据完美结合,产生了冯诺依曼体系计算机。这和人类似,仔细一想,人的大脑也有计算和存储功能。
杂谈:
两年前看了《黑客与画家》这本书,当时觉得非常有趣,书的后半部分 作者大力鼓吹Lisp语言,说了lisp语言是未来的编程语言,极度抽象,能非常省力的做到其他语言很难做到或根本做不到的事情。
其中举了一个很贴切的例子,他写了一段简短的lisp代码,参数是一个函数,返回值也是一个函数。也就是能够将函数当做数据进行处理。相当于把代码当做数据进行处理。
这个能力是非常有吸引力的,在C++中,代码就是.text,数据就是.data,区分的非常明显。而在lisp中,代码和数据没有明显的区分。
有人称lisp为面向语言的语言、函数式编程的鼻祖、变态的语言、非正常人使用的语言......
lisp的确吸引了我,作者说最值钱的是人力,所以把事情尽可能多的交给程序去做,lisp正是这样一门语言,它能将算法当做数据来用,所以它能在人工智能领域施展拳脚。
当我尝试去学lisp时,发现它的代码全是括号,表达式(+ 3 4)的结果是7,而正常的语言都是3+4。所以读lisp代码感觉有些困难。最后我没有使用lisp。但是我还是愿意称它为函数式编程的鼻祖。
近年来,函数式编程被众多语言接受,python就支持函数式。今天我要说的是我经常用的C++所支持的函数式。
我仔细想,为啥lisp如此灵活的把函数和数据结合起来。最后想出来,lisp和python都是动态语言,在运行时才生成指令,所以运行的时候可以动态生成代码。而C++是静态语言,在编译期就把指令定死了。所以C++如果支持函数式编程,那一定是在编译器决定下来了。
果然,从C语言的函数指针,到C++的函数对象,再到C++11的lambda、functional、bind。都是在编译器完成的函数式,及通过元编程(宏定义、模板)实现。
函数装饰器:
在《黑客与画家》中作者贴出来的lisp代码,正是一个函数装饰器,及接受一个函数,对这个函数进行修改,再返回一个新的函数。这个功能就称为函数装饰器。当时他认为C++是完全实现不了这个功能的,我尝试了很多次,的确实现不出来,但是最近在ceph代码中发现了函数装饰器的影子,虽然没有lisp的简洁,但是功能还是实现出来了:下面我就直接贴代码吧。
#include <utility> class Decorator { public: template <typename Callback, typename...Args> decltype(auto) ret(Callback&& cb, Args&&... args) { //log printf("begin "); printf("to do some things "); auto ret = std::forward<Callback>(cb)(std::forward<Args>(args)...); //log printf("end "); printf("to do some things "); return ret; } template <typename Callback, typename...Args> void voi(Callback&& cb, Args&&... args) { //log printf("begin "); printf("to do some things "); std::forward<Callback>(cb)(std::forward<Args>(args)...); //log printf("end "); printf("to do some things "); } }; int add(int a, int b) { return a + b; } void sub(int a, int b) {} int main() { Decorator dec; dec.ret(add, 1, 3); dec.voi(sub, 1, 3); system("pause"); return 0; }
其中,ret函数模板可以封装 有返回值的函数,voi函数模板可以封装 无返回值的函数。可以自行体会, 然后根据自己的需求进行修改。