高端函数用得广泛么?

48 views
Skip to first unread message

g9yuayon

unread,
Nov 10, 2007, 10:08:33 AM11/10/07
to TopLanguage
昨天用JavaScript写的Parser Combinator库在code review时被批评了。原因是"太复杂"。和同事讨论了一下,用他
的话说,Closure/高端函数这种东西太复杂,没人懂,没人愿意学,也没人需要学。我写的Parser Combinator除了我以外,没人能够
维护。我争辩库里每个函数连注释都不超过20行。用了这套工具可以用申明式的风格写出非常简单的解析代码。比如匹配一个10进位数(+|-)?(.\d
+|(\d+(\.\d+)?)只需要段段4行。这比每个人需要解析时就写冗长嵌套的循环简单。但他说大家至少能够理解循环,可以调试循环。而没人能理
解parser combinator。当时还是有点吃惊,因为我一直以为高端函数是JavaScript里最强有力的工具。还有副作用就是居然为了追
求简洁,反而落下了"追求复杂"的名声。:-D

所以我想问:高端函数到底用得广么?不说其它语言了。就说JavaScript吧。毕竟流行的语言里就JavaScript有方便的高端函数。另外怎么
教育我们部门的老大们嗫?现在是的问题是他们缺乏动力,所以办学习班或者写文章基本没有,因为别人根本不会参见或者读。

几点澄清:

1. 我的同事懂Closure、高端函数这些东西。他非常厉害,编程快,代码质量高,经验丰富,经常想出比我的方法更简单的方法。他批评的原因完全出
于务实的考虑。

2. 我们用的是类似Flex的东西。JavaScript是粘合剂。在JavaScript基础上还有Class,所以并不一定非用高端函数。不过用
OO模拟函数在这里还是复杂了点。看JParsec就知道了。

3. 我们用的JavaScript不支持标准里的Regex。JavaScript也没有好的基本解析函数,比如说解析整数
(parseInt(09)返回0, parseInt('9#¥#¥')返回9,嘿嘿。这也是我写parse combinator的动机之一。本来
还准备把库改成支持pakrat语法,用空间换时间的。看来没有必要了。

4. 我其实只需要验证decimal,所以写一个parse combinator也有点过了。不过我想的是马上要做日期和时间的全球化支持,正好用
得上。而且总有其它地方需要规定文本的pattern吧。属于长远投资的说。这点就见仁见义了。说我犯了编程第一大错:over
abstraction,也无不可。

g9yuayon

unread,
Nov 10, 2007, 10:09:42 AM11/10/07
to TopLanguage
P.S., 我用email回复帖子,被据。说没有权限。未鹏给个权限吧。Orz

g9yuayon

unread,
Nov 10, 2007, 2:47:07 PM11/10/07
to TopLanguage
发现一件让自己很可耻的事:JavaScript里解析数字,Number(value)加上一点处理特殊情况的代码就够了。用不着什么
parsing。

pongba

unread,
Nov 10, 2007, 10:46:45 PM11/10/07
to pon...@googlegroups.com
On Nov 10, 2007 11:09 PM, g9yuayon <yyc...@gmail.com> wrote:
P.S., 我用email回复帖子,被据。说没有权限。未鹏给个权限吧。Orz
我看了一下,似乎可以啊。好像不需要我加什么权限就可以mail回帖吧。被拒的消息是什么?:0)
Anyway,你是说另一个邮件地址吗?我也invite了一下:)

--
刘未鹏(pongba)|C++的罗浮宫
http://blog.csdn.net/pongba
TopLanguage
http://groups.google.com/group/pongba

Yong Yuan

unread,
Nov 10, 2007, 11:15:34 PM11/10/07
to pon...@googlegroups.com
对啊。我的这个帐户有两个email地址。我混着用,自己都晕了。谢谢未鹏。

pongba

unread,
Nov 11, 2007, 2:19:41 AM11/11/07
to pon...@googlegroups.com
On Nov 10, 2007 11:08 PM, g9yuayon <yyc...@gmail.com> wrote:
昨天用JavaScript写的Parser Combinator库在code review时被批评了。原因是"太复杂"。和同事讨论了一下,用他
的话说,Closure/高端函数这种东西太复杂,没人懂,没人愿意学,也没人需要学。我写的Parser Combinator除了我以外,没人能够
维护。我争辩库里每个函数连注释都不超过20行。用了这套工具可以用申明式的风格写出非常简单的解析代码。比如匹配一个10进位数(+|-)?(.\d
+|(\d+(\.\d+)?)只需要段段4行。这比每个人需要解析时就写冗长嵌套的循环简单。但他说大家至少能够理解循环,可以调试循环。而没人能理
解parser combinator。
这个观点让我想起和7猫的关于异常和C++的争论。以及和cber关于异常的争论。
后来我的观点是,如果真的没有人有理解closure的能力且也不愿意理解的话(这个条件对任何非平凡的抽象机制都成立),stick to最小公分母也许是没有办法的办法。
我觉得这里问题其实很简单:要么教会他们理解closure,要么抛弃这个工具。
先说教会他们closure:一个人要想学一个东西一定要有一个动机,如果能够提供一个非常强的动机,就算复杂,他们也会学习。那么,对于closure,动机是什么呢?再则,从反面来看,他们为什么不愿意学?是因为觉得理解起来复杂。那么只要你能够用一个简单(非常简单)的例子说服他们其实closure很简单,那么这个障碍或许就可以移除。不过,生物是很固执的:-)

4. 我其实只需要验证decimal,所以写一个parse combinator也有点过了。不过我想的是马上要做日期和时间的全球化支持,正好用
得上。而且总有其它地方需要规定文本的pattern吧。属于长远投资的说。这点就见仁见义了。说我犯了编程第一大错:over
abstraction,也无不可。

从针对最常见场景设计的思想来说,的确,要parse一个decimal,使用regex类似的语法是overwhelming了。不符合"简单的事情应该是简单的"思想:-) 如果我是用户,我会希望直接调用一个parse函数就搞定了:) 所以你不妨增加这样一个简单的函数,并在这个函数内部用combinator来实现:-)

Yong Yuan

unread,
Nov 11, 2007, 3:02:50 AM11/11/07
to pon...@googlegroups.com
当然是加了一个函数,isNumber(),供用户调用。不过这件事本身是我的错,可以用Number()函数轻松实现的,就不该用parser combinator。我吃惊的是简单的高端函数应用收到那么强烈的批评。于是好奇到底公司里有多少人熟练使用甚至开始接受高端函数了。另外我坚信Closure好用得很。大家不肯学是没有上面来的压力。公司大了,自顶向下的推广方式才有用。上面架构都用函数编程了,估计下面的喽罗们马上就学会。要想让同事们花时间学Closure,肯定是不现实的,除非项目里有大量非函数编程不可的需求。问题是,有了OO后,对很多人来说跟没有必要用高端函数了。毕竟对象就是只有一个方法,apply(), 的函数。:-)

red...@gmail.com

unread,
Nov 11, 2007, 3:25:07 AM11/11/07
to pon...@googlegroups.com
我觉得用 regex 是合适的.

用简单的函数处理起来当然更简单, 但是这带来额外的学习和记忆的成本. 不如使用 well known 的东西.

就像一个50000行的 C++ 代码中, 如果有2000用 embedded python 去做, 会非常简单, 非常 native, 但是我可能不会选择这样做, 相比给项目来的额外的复杂度, 并不合算. 如果有 20000 行的话, 我应该会做了.




从针对最常见场景设计的思想来说,的确,要parse一个decimal,使用regex类似的语法是overwhelming了。不符合"简单的事情应 该是简单的"思想:-) 如果我是用户,我会希望直接调用一个parse函数就搞定了:) 所以你不妨增加这样一个简单的函数,并在这个函数内部用combinator来实现:-)


Yong Yuan

unread,
Nov 11, 2007, 3:58:22 AM11/11/07
to pon...@googlegroups.com
我们系统中的JavaScript是不支持Regex的。这也是我写这个parser combinator库的动机之一。:=)

On Nov 11, 2007 3:25 AM, <red...@gmail.com> wrote:
我觉得用 regex 是合适的.

用简单的函数处理起来当然更简单, 但是这带来额外的学习和记忆的成本. 不如使用 well known 的东西.

就像一个50000行的 C++ 代码中, 如果有2000用 embedded python 去做, 会非常简单, 非常 native, 但是我可能不会选择这样做, 相比给项目来的额外的复杂度, 并不合算. 如果有 20000 行的话, 我应该会做了.




从针对最常见场景设计的思想来说,的确,要parse一个decimal,使用regex类似的语法是overwhelming了。不符合"简单的事情应该是简单的"思想:-) 如果我是用户,我会希望直接调用一个parse函数就搞定了:) 所以你不妨增加这样一个简单的函数,并在这个函数内部用combinator来实现:-)





red...@gmail.com

unread,
Nov 11, 2007, 4:14:01 AM11/11/07
to pon...@googlegroups.com
哈, 哈, 那如果你这个parser combinator 的学习难度不是特别高, 并且文档中列出了 80% 常用情形不用动脑直接可以参考, 我可就不会去写循环处理了 :)

Yong Yuan 写道:
我们系统中的JavaScript是不支持Regex的。这也是我写这个parser combinator库的动机之一。:=)

On Nov 11, 2007 3:25 AM, <red...@gmail.com> wrote:
我觉得用 regex 是合适的.

用简单的函数处理起来当然更简单, 但是这带来额外的学习和记忆的成本. 不如使用 well known 的东西.

就像一个50000行的 C++ 代码中, 如果有2000用 embedded python 去做, 会非常简单, 非常 native, 但是我可能不会选择这样做, 相比给项目来的额外的复杂度, 并不合算. 如果有 20000 行的话, 我应该会做了.




从针对最常见场景设计的思想来说,的确,要parse一个decimal,使用regex类似的语法是overwhelming了。不符合"简单的事情应 该是简单的"思想:-) 如果我是用户,我会希望直接调用一个parse函数就搞定了:) 所以你不妨增加这样一个简单的函数,并在这个函数内部用combinator来实现:-)

yq chen

unread,
Nov 11, 2007, 4:54:21 AM11/11/07
to pon...@googlegroups.com
或许简单的方法就是最好的办法。

在07-11-11,red...@gmail.com <red...@gmail.com> 写道:
哈, 哈, 那如果你这个parser combinator 的学习难度不是特别高, 并且文档中列出了 80% 常用情形不用动脑直接可以参考, 我可就不会去写循环处理了 :)

Yong Yuan 写道:
我们系统中的JavaScript是不支持Regex的。这也是我写这个parser combinator库的动机之一。:=)

On Nov 11, 2007 3:25 AM, <red...@gmail.com> wrote:
我觉得用 regex 是合适的.

用简单的函数处理起来当然更简单, 但是这带来额外的学习和记忆的成本. 不如使用 well known 的东西.

就像一个50000行的 C++ 代码中, 如果有2000用 embedded python 去做, 会非常简单, 非常 native, 但是我可能不会选择这样做, 相比给项目来的额外的复杂度, 并不合算. 如果有 20000 行的话, 我应该会做了.




从针对最常见场景设计的思想来说,的确,要parse一个decimal,使用regex类似的语法是overwhelming了。不符合"简单的事情应该是简单的"思想:-) 如果我是用户,我会希望直接调用一个parse函数就搞定了:) 所以你不妨增加这样一个简单的函数,并在这个函数内部用combinator来实现:-)


oldrev

unread,
Nov 11, 2007, 6:36:17 AM11/11/07
to pon...@googlegroups.com
换 Ruby。

在 2007-11-10六的 15:08 +0000,g9yuayon写道:

--
"Live Long and Prosper"
- oldrev

莫华枫

unread,
Nov 11, 2007, 7:04:40 AM11/11/07
to pon...@googlegroups.com
对未知的恐惧吞噬着我们的心灵。:-D
这种事情也发生在我向同事们推广一些设计模式和gp的技术应用的时候。
到目前为止,我称得上"会用"的语言只有C++。但是标准算法用得越多,就越看到Closure之类的作用。Closure使得算法成为真正"可组装"的东西。(可组装啊,构造算法可以像装pc那样容易,太容易了)。要是C++里函数是first-class的,那事情就更完美了。


在07-11-11,Yong Yuan <y...@cs.toronto.edu> 写道:



--
反者道之动,弱者道之用
m...@seaskysh.com
longsh...@gmail.com
http://blog.csdn.net/longshanks/

Jian Wang

unread,
Nov 11, 2007, 7:11:10 AM11/11/07
to pon...@googlegroups.com
对的。现在的boost::lambda太难用,调用一个成员函数,或者访问一个成员变量就麻烦的要命。觉得还是BOOST FOREACH好用。


在 07-11-11,莫华枫<longsh...@gmail.com> 写道:

莫华枫

unread,
Nov 11, 2007, 8:34:06 AM11/11/07
to pon...@googlegroups.com
我还遇到过一件更夸张的事:鉴于公司软件代码中大段大段的switch-case调用分派,我建议同僚们使用数组或关联容器+OOP多态加以替代。有人就对我说:你这样效率会怎么样?我告诉他,用数组,效率肯定不用说了,用hash的话是常数复杂度。不然,即便用map的话也是对数复杂度的。他的反应是一脸不屑地摇头。我无语...

在07-11-11, Jian Wang <oxygen.j...@gmail.com> 写道:

何源

unread,
Nov 11, 2007, 10:39:04 AM11/11/07
to TopLanguage
同意楼上。boost::lambda用起真的不太爽。关键用了还要写一段注释说明,要不别人就看不大懂。
Closure这种东西之所以总是小范围的流行,还是大多数程序员没有函数编程的学习背景(再次问候国内高校计算机教学的妈妈)。我们现在接触大JS程
序员基本上没有这种思想。
Ruby中的Closure倒是很强,随着Ruby流行,函数编程的思想可能会流行起来的。

王磊

unread,
Nov 11, 2007, 8:29:35 PM11/11/07
to pon...@googlegroups.com
现在大部分国内的公司都是在做产品而不是做研发,所以大环境下就是新技术少用,复杂的技术不用。除非逼不得已。所以周围人都是让你看原来是怎么做的,现在还要怎么做。日~
估计再有2年我们公司也不会用上ruby

 
在07-11-11,何源 <he.yuan...@gmail.com> 写道:

zhangy...@kedacom.com

unread,
Nov 11, 2007, 8:32:15 PM11/11/07
to pon...@googlegroups.com

我这就一直是vc++6.0

Yong Yuan

unread,
Nov 11, 2007, 11:58:56 PM11/11/07
to pon...@googlegroups.com
我们公司做研发。我们用的语言就是JavaScript的变种。所以才郁闷:居然放弃JavaScript里最受人称道的功能.

莫华枫

unread,
Nov 12, 2007, 12:18:56 AM11/12/07
to pon...@googlegroups.com
唉,想想牛顿第一定律吧。:(

在07-11-12,Yong Yuan <y...@cs.toronto.edu> 写道:

Atry

unread,
Nov 12, 2007, 8:14:41 AM11/12/07
to pon...@googlegroups.com
我觉得如果只有不多的几个选项的话, switch-case 也没错吧,至少避免了耦合层。不过我们公司处理网络的那个代码,那个 switch-case 可是相当长,太可怕了。
如果取代 switch-case ,建议用排序的vector + lower_bound ,vector 里面放进函数指针,或者接口指针。

在07-11-11, 莫华枫 <longsh...@gmail.com> 写道:

莫华枫

unread,
Nov 12, 2007, 8:22:02 AM11/12/07
to pon...@googlegroups.com
如果就那么三五个,我也就不费那事了。唉,关键不在多少。作为一个程序员,应该了解这些技术,并且做出正确的选择。而不应该一味地排斥。

在07-11-12,Atry <pop....@gmail.com> 写道:

oldrev

unread,
Nov 12, 2007, 8:23:03 AM11/12/07
to pon...@googlegroups.com
用 int 模板参数来分派

On Sun, 2007-11-11 at 21:34 +0800, 莫华枫 wrote:
> 我还遇到过一件更夸张的事:鉴于公司软件代码中大段大段的switch-case调用
> 分派,我建议同僚们使用数组或关联容器+OOP多态加以替代。有人就对我说:你
> 这样效率会怎么样?我告诉他,用数组,效率肯定不用说了,用hash的话是常数
> 复杂度。不然,即便用map的话也是对数复杂度的。他的反应是一脸不屑地摇

Atry

unread,
Nov 12, 2007, 8:34:30 AM11/12/07
to pon...@googlegroups.com
boost 将要 review 一个 switch 库,用 boost::fusion::tuple 来搞的,也可以。我也写了一个 D 的 SwitchTuple http://www.dsource.org/projects/tango/ticket/675

在07-11-12,Atry <pop....@gmail.com> 写道:

莫华枫

unread,
Nov 12, 2007, 8:48:58 AM11/12/07
to pon...@googlegroups.com
唉,哪里还敢提模板哦。再说C#也没有模板。

在07-11-12,oldrev <old...@gmail.com> 写道:

katkat lim

unread,
Nov 12, 2007, 7:34:12 PM11/12/07
to pon...@googlegroups.com
C#有模板啊,只是那种模板看着像语法糖,跟C++的模板不是一个级别的。

莫华枫

unread,
Nov 12, 2007, 7:40:40 PM11/12/07
to pon...@googlegroups.com
这样的话,我还能叫它"模板"吗?:)

在07-11-13,katkat lim <limk...@gmail.com> 写道:

oldrev

unread,
Nov 12, 2007, 7:55:08 PM11/12/07
to pon...@googlegroups.com
人家叫 "Generics" 不是 "Template"

katkat lim

unread,
Nov 12, 2007, 8:01:54 PM11/12/07
to pon...@googlegroups.com

书上还是叫它模板。

莫华枫

unread,
Nov 12, 2007, 8:06:11 PM11/12/07
to pon...@googlegroups.com
ms自己叫它generic,C#标准也叫它generic。.net里也叫generic。而且,C++/CLI里有generic,也有template。所以,我们还是叫它generic吧。尽管它也不是合格的generic

Googol Lee

unread,
Nov 12, 2007, 9:55:25 PM11/12/07
to TopLanguage
这个是由于c#的模板不支持特化导致的吧?无法在语义上形成编译期的匹配选择。

On Nov 13, 9:06 am, "莫华枫" <longshank...@gmail.com> wrote:
> ms自己叫它generic,C#标准也叫它generic。.net里也叫generic。而且,C++/CLI里有generic,也有template。所以,我们还是叫它generic吧。尽管它也不是合格的generic
>

> 在07-11-13,katkat lim <limkat...@gmail.com> 写道:


>
>
>
> > 书上还是叫它模板。
> > On 11/13/07, oldrev <old...@gmail.com> wrote:
>
> > > 人家叫 "Generics" 不是 "Template"
>
> > > On Tue, 2007-11-13 at 08:40 +0800, 莫华枫 wrote:
> > > > 这样的话,我还能叫它"模板"吗?:)
>

> > > > 在07-11-13,katkat lim <limkat...@gmail.com > 写道:
> > > > C#有模板啊,只是那种模板看着像语法糖,跟C++的模板不是一个级别
> > > > 的。


>
> > > > On 11/12/07, 莫华枫 <longshank...@gmail.com> wrote:
> > > > 唉,哪里还敢提模板哦。再说C#也没有模板。
>
> > > > 在07-11-12,oldrev <old...@gmail.com> 写道:
> > > > 用 int 模板参数来分派
>
> > > > On Sun, 2007-11-11 at 21:34 +0800, 莫华枫
> > > > wrote:
> > > > > 我还遇到过一件更夸张的事:鉴于公司软件代码中
> > > > 大段大段的switch-case调用
> > > > > 分派,我建议同僚们使用数组或关联容器+OOP多态
> > > > 加以替代。有人就对我说:你
> > > > > 这样效率会怎么样?我告诉他,用数组,效率肯定
> > > > 不用说了,用hash的话是常数
> > > > > 复杂度。不然,即便用map的话也是对数复杂度
> > > > 的。他的反应是一脸不屑地摇
> > > > > 头。我无语...
>
> > > > > 在07-11-11,Jian Wang

> > > > <oxygen.jian.w...@gmail.com> 写道:


> > > > > 对的。现在的boost::lambda太难
> > > > 用,调用一个成员函数,或者
> > > > > 访问一个成员变量就麻烦的要命。觉得还
> > > > 是BOOST FOREAC
> > > > > H好用。
>
> > > > > 在 07-11-11,莫华枫<

> > > > longshank...@gmail.com> 写道:

> > > > g9yuayon < yycs...@gmail.com>

> ...
>
> read more

Reply all
Reply to author
Forward
0 new messages