虎大博(www.hudabo.com)是一家专业收集各种游戏平台优惠信息的导航网站,可以给您推荐最新的注册送白菜/首存优惠信息,同时还能保障您的资金安全。所谓白象,“white elephant”,是指被人奉为神圣,价格昂贵,却没有实际用处的东西。函数式语言里面有很好的东西,然而它们里面有很多多余的特性,这些特性跟白象的性质类似。
函数式语言的“拥护者”们,往往认为这个世界本来应该是“纯”(pure)的,不应该有任何“副作用”。他们把一切的“赋值操作”看成低级弱智的作法。他们很在乎所谓尾递归,类型推导,fold,currying,maybe type等等。他们以自己能写出使用这些特性的代码为豪。可是殊不知,那些东西其实除了能自我安慰,制造高人一等的幻觉,并不一定能带来真正优秀可靠的代码。
纯函数半壶水都喜欢响叮当。很多喜欢自吹为“函数式程序员”的人,往往并不真的理解函数式语言的本质。他们一旦看到过程式语言的写法就嗤之以鼻。比如以下这个C函数:
int f(int x) { int y = 0; int z = 0; y = 2 * x; z = y + 1; return z / 3; } 很多函数式程序员可能看到那几个赋值操作就皱起眉头,然而他们看不到的是,这是一个真正意义上的“纯函数”,它在本质上跟Haskell之类语言的函数是一样的,也许还更加优雅一些。
盲目鄙视赋值操作的人,也不理解“数据流”的概念。其实不管是对局部变量赋值还是把它们作为参数传递,其实本质上都像是把一个东西放进一个管道,或者把一个电信号放在一根导线上,只不过这个管道或者导线,在不同的语言范式里放置的方向和样式有一点不同而已!
对数据结构的忽视函数式语言的帮众没有看清楚的另一个重要的,致命的东西,是数据结构的根本性和重要性。数据结构的有些问题是“物理”和“本质”地存在的,不是换个语言或者换个风格就可以奇迹般消失掉的。函数式语言的拥护者们喜欢盲目的相信和使用列表(list),而没有看清楚它的本质以及它所带来的时间复杂度。列表带来的问题,不仅仅是编程的复杂性。不管你怎么聪明的使用它,很多性能问题是根本没法解决的,因为列表的拓扑结构根本就不适合用来干有些事情!
从数据结构的角度看,Lisp所谓的list就是一个单向链表。你必须从上一个节点才能访问下一个,而这每一次“间接寻址”,都是需要时间的。在这种数据结构下,很简单的像length或者append之类函数,时间复杂度都是O(n)!为了绕过这数据结构的不足,所谓的“Lisp风格”告诉你,不要反复append,因为那样复杂度是O(n2)。如果需要反复把元素加到列表末尾,那么应该先反复cons,然后再reverse一下。很可惜的是,当你同时有递归调用,就会发现cons+reverse的做法颠来倒去的,非常容易出错。有时候列表是正的,有时候是反的,有时候一部分是反的…… 这种方式用一次还可以,多几层递归之后,自己都把自己搞糊涂了。好不容易做对了,下次修改可能又会出错。然而就是有人喜欢显示自己聪明,喜欢自虐,迎着这类人为制造的“困难”勇往直前 :)
函数式语言的“拥护者”们,往往认为这个世界本来应该是“纯”(pure)的,不应该有任何“副作用”。他们把一切的“赋值操作”看成低级弱智的作法。他们很在乎所谓尾递归,类型推导,fold,currying,maybe type等等。他们以自己能写出使用这些特性的代码为豪。可是殊不知,那些东西其实除了能自我安慰,制造高人一等的幻觉,并不一定能带来真正优秀可靠的代码。
纯函数半壶水都喜欢响叮当。很多喜欢自吹为“函数式程序员”的人,往往并不真的理解函数式语言的本质。他们一旦看到过程式语言的写法就嗤之以鼻。比如以下这个C函数:
int f(int x) { int y = 0; int z = 0; y = 2 * x; z = y + 1; return z / 3; } 很多函数式程序员可能看到那几个赋值操作就皱起眉头,然而他们看不到的是,这是一个真正意义上的“纯函数”,它在本质上跟Haskell之类语言的函数是一样的,也许还更加优雅一些。
盲目鄙视赋值操作的人,也不理解“数据流”的概念。其实不管是对局部变量赋值还是把它们作为参数传递,其实本质上都像是把一个东西放进一个管道,或者把一个电信号放在一根导线上,只不过这个管道或者导线,在不同的语言范式里放置的方向和样式有一点不同而已!
对数据结构的忽视函数式语言的帮众没有看清楚的另一个重要的,致命的东西,是数据结构的根本性和重要性。数据结构的有些问题是“物理”和“本质”地存在的,不是换个语言或者换个风格就可以奇迹般消失掉的。函数式语言的拥护者们喜欢盲目的相信和使用列表(list),而没有看清楚它的本质以及它所带来的时间复杂度。列表带来的问题,不仅仅是编程的复杂性。不管你怎么聪明的使用它,很多性能问题是根本没法解决的,因为列表的拓扑结构根本就不适合用来干有些事情!
从数据结构的角度看,Lisp所谓的list就是一个单向链表。你必须从上一个节点才能访问下一个,而这每一次“间接寻址”,都是需要时间的。在这种数据结构下,很简单的像length或者append之类函数,时间复杂度都是O(n)!为了绕过这数据结构的不足,所谓的“Lisp风格”告诉你,不要反复append,因为那样复杂度是O(n2)。如果需要反复把元素加到列表末尾,那么应该先反复cons,然后再reverse一下。很可惜的是,当你同时有递归调用,就会发现cons+reverse的做法颠来倒去的,非常容易出错。有时候列表是正的,有时候是反的,有时候一部分是反的…… 这种方式用一次还可以,多几层递归之后,自己都把自己搞糊涂了。好不容易做对了,下次修改可能又会出错。然而就是有人喜欢显示自己聪明,喜欢自虐,迎着这类人为制造的“困难”勇往直前 :)