锁定老帖子 主题:Java 语言中的函数编程
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-09-17
值得阅读,有深度,深有所得。
楼主的不辞辛苦的介绍为我等打开了一扇新的窗户。感激不尽,建议加精。 |
|
返回顶楼 | |
发表时间:2004-09-17
恩,既然已经讲到了Monads,看来不讲一下Y Combinator,fix point,总觉得有些对不起大家。但是考虑到这个问题是出了名的累死人不陪命....。这样吧我出一个小题目,看看大家能不能够看懂,如果看得懂的人多呢就讲了,如果少的话就不说了。
def cfold1(fun,z,list);: if(len(list);==0);: return z else: return fun(list.pop();,z,lambda y:cfold1 (fun,y,list);); def cfold(Operator,z,l);: return cfold1(lambda x,t,g:Operator(x,g(t););,z,l); if __name__=="__main__": print cfold(lambda x,y:x+y,0,[1,2,3,4]); 我现在已经能够想象到屏幕前面对这个程序时你的抓狂程度。 |
|
返回顶楼 | |
发表时间:2004-09-17
Trustno1 写道 不考虑数据,是算法的算法 递归是最主要的逻辑结构 在FP里面我们可以把函数当作抽象的逻辑,这些逻辑独立于数据。然后对这些逻辑进行编程组合,得到一个新的逻辑或者算法。FP也可以说成是针对逻辑的编程,而Java/C++这些可以说是针对数据的编程。 因此我们可以看到其实算子空间本身具有的性质就是N维正交。也就是说每个算子都是独立互不干扰的。他不会有OO那样牵扯不清的各种问题。 而FP不一样,他所有的代码都是一片一小片的片断,首先这些小片段的改动将比动整个金字塔来的更加容易,其次这些小片断天生就是独立正交不相互干扰,我修改了mother,不会干扰father,而OO要做到这样就要动用接口,模式这种非常笨重的方法。 几个问题: 1.上面的例子中没有明显的感觉到"不考虑数据"这个特性!我所理解的是不考虑数据,不光是不考虑数据的值,当然也包括数据的类型。不知具体指的什么?(也可能是我思考不够深入,原谅) 2.我学编译的时候只学过用if和for实现递归,倒从来没考虑过怎么用递归来实现if和for,看来FP把他们都放到表达式一层了。不知我的理解是否正确? 3.我对算子空间的理解本来是一个包含不同映射关系的集合,可后面解释的时候似乎又变成了值域的集合,有点糊涂啦。我觉得还是说映射关系的集合更好一点,因为值域本身就是一个集合啦。虽然意思一样,但理解起来容易混淆。 下面给出一段用java实现的“独立互不干扰”的代码片断,用了decorator pattern,例子来自 Steve Metsker的Design Patterns Java Workbook (http://www.oozinoz.com) 别说我做广告哦:wink: 哪位感兴趣的话代码可以去上面的网址下载 这个是decorator的核。 package com.oozinoz.function; /* * Copyright (c); 2001 Steven J. Metsker. * * Steve Metsker makes no representations or warranties about * the fitness of this software for any particular purpose, * including the implied warranty of merchantability. * * Please use this software as you wish with the sole * restriction that you may not claim that you wrote it. */ /** * This abstract superclass defines the role of a function * that wraps itself around (or "decorates"); another function. * * @author Steven J. Metsker */ public abstract class Function { protected Function[] source; /** * Construct a function that decorates the provided source * functions. * * @param Function[] the source functions that this function * wraps */ public Function(Function[] source); { this.source = source; } /** * Construct a function that decorates the provided source * function. * * @param Function the source function that this function * wraps */ public Function(Function f); { this(new Function[] { f });; } /** * Return true if these functions are of the same class * and their source functions are equal. * * @return true if these functions are of the same class * and their source functions are equal */ public boolean equals(Object o); { if (!getClass();.equals(o.getClass(););); { return false; } Function f = (Function); o; for (int i = 0; i < source.length; i++); { if (!source[i].equals(f.source[i]);); { return false; } } return true; } /** * Apply this object's represented function to the source * function(s); at the given time and return the result. * * @param t the time function that goes 0 to 1 and that * other functions use as a parameter * * @return the result of applying this object's represented * function to the source function(s); at time t */ public abstract double f(double t);; /** * Return a textual representation of this function. * * @return a textual representation of this function */ public String toString(); { String name = getClass();.getName();; String name2 = name.substring(name.lastIndexOf('.'); + 1);; StringBuffer buf = new StringBuffer(name2);; if (source.length > 0); { buf.append('(');; for (int i = 0; i < source.length; i++); { if (i > 0); { buf.append(", ");; } buf.append(source[i]);; } buf.append(');');; } return buf.toString();; } } 下面是两个独立的算子 package com.oozinoz.function; /* * Copyright (c); 2001 Steven J. Metsker. * * Steve Metsker makes no representations or warranties about * the fitness of this software for any particular purpose, * including the implied warranty of merchantability. * * Please use this software as you wish with the sole * restriction that you may not claim that you wrote it. */ /** * Wrap the Math.abs(); function around a given source. * * @author Steven J. Metsker */ public class Abs extends Function { /** * Construct an absolute value function that decorates the * provided source function. * * @param Function the source function that this function * wraps */ public Abs(Function f); { super(f);; } /** * Return Math.abs(); applied to the source function's value * at time t. * * @param t the time function that goes 0 to 1 and that * other functions use as a parameter * * @return Math.abs(); applied to the source function's value * at time t. */ public double f(double t); { return Math.abs(source[0].f(t););; } } package com.oozinoz.function; /* * Copyright (c); 2001 Steven J. Metsker. * * Steve Metsker makes no representations or warranties about * the fitness of this software for any particular purpose, * including the implied warranty of merchantability. * * Please use this software as you wish with the sole * restriction that you may not claim that you wrote it. */ /** * Wrap an arithmetic function around a pair of given sources. * * @author Steven J. Metsker */ public class Arithmetic extends Function { protected char operator; /** * Construct an arithmetic function that decorates the * provided source functions. * * @param char the operator to apply (+ - * /); * * @param Function the first source function that this * function wraps * * @param Function the second source function */ public Arithmetic( char operator, Function f1, Function f2); { super(new Function[] { f1, f2 });; this.operator = operator; } /** * Return the result of applying this objects' arithmetic * operator (+ - * /); to the source functions' values * at time t. * * @param t the time function that goes 0 to 1 and that * other functions use as a parameter * * @return the result of applying this objects' arithmetic * operator (+ - * /); to the source functions' values * at time t */ public double f(double t); { switch (operator); { case '+' : return source[0].f(t); + source[1].f(t);; case '-' : return source[0].f(t); - source[1].f(t);; case '*' : return source[0].f(t); * source[1].f(t);; case '/' : return source[0].f(t); / source[1].f(t);; default : return 0; } } } 说实话,我并不觉得算子实现起来特别的复杂,当然,比FP是不如的。不过我觉得fp的长处似乎在于科学计算,处理业务逻辑的时候,我还是更希望看到结构明晰的处理逻辑,而不是简单的表达式,会让我这种智商的人犯晕(已经超过80了,算正常人)。任何语言都有它的目标,硬要拿长处和短处比是不公正的。 还是很感谢Trustno1带给我这么精彩的内容,我是觉得很有深度啦 |
|
返回顶楼 | |
发表时间:2004-09-17
引用 1.上面的例子中没有明显的感觉到"不考虑数据"这个特性!我所理解的是不考虑数据,不光是不考虑数据的值,当然也包括数据的类型。不知具体指的什么?(也可能是我思考不够深入,原谅) 数据的值,是需要考虑的,数据的类型在Haskell这样的强类型FP中同样要考虑。我说的不考虑数据的意思是不考虑数据的状态维护。 引用 2.我学编译的时候只学过用if和for实现递归,倒从来没考虑过怎么用递归来实现if和for,看来FP把他们都放到表达式一层了。不知我的理解是否正确? FP不是表达式,而是一系列的规则。例如你用Java写一个Fibonacci的递归函数其实就是一个FP,只是他没有用FP语言罢了。至于流式控制和递归之间的转换问题,请看这个帖子。 http://forum.iteye.com/viewtopic.php?t=6551&highlight= 递归的表达要比imperative的要好,而且速度和效率等价于imperative语言。 引用 3.我对算子空间的理解本来是一个包含不同映射关系的集合,可后面解释的时候似乎又变成了值域的集合,有点糊涂啦。我觉得还是说映射关系的集合更好一点,因为值域本身就是一个集合啦。虽然意思一样,但理解起来容易混淆。 你可以这样理解,{f(x)|x->{g(x),g1(x),g2(x)}}。这里后面那个集合就是一个算子空间,每个g(x)就是一个算子。 至于那个Java实现,我就不多说了。在Java里面实现这种东西,没有多大的意义。很多功能都不能做,就是能做也是麻烦的要死。模拟FP是一回事情,正真的FP是另外一回事情。你可以去ABP看看,哪里有个搞ASM的家伙,用MASM模拟 OO而且模拟的还不赖,但是你就不能说汇编语言是OO语言吧。 要在Java中实现FP唯一的一种途径是使用基于JVM的规则语言,例如JSR-94里面的几个候选标准,说不定groovy也可以但是我没有学过不好说。 至于FP有没有用这个问题,关键是看你在那里用。其实我们经常使用XSLT就是一种FP,再说了XSLT还不是再处理Business Logic,而是UI。至于业务逻辑的处理用哪个好,如果你不是很复杂的逻辑,那么用那个都无所谓。就像你高中时后的运动学方程不会用到相对论一样,虽然相对论也能推出牛顿定律但那个东西只能是大炮打蚊子。如果逻辑非常复杂的例如CRM中的一些数据过滤等等,一般都采用规则引擎,如果要用imperative的代码根本没法写。这方面BPM是应用最广泛的地方,JSR-94就是为了简化BPM而实现的规则引擎.你可以去读读JSR-94的规范,你会发现我们通常写的那些OO对象在这个规范里面就变成了一个个的算子。然后通过这个规范的规则将他们粘合起来。而这种粘合的规则实际上就是一种FP。Osis的RML和BRML 也是一种FP,只不过用XML标记描述罢了. |
|
返回顶楼 | |
发表时间:2004-09-17
Trustno1 写道 恩,既然已经讲到了Monads,看来不讲一下Y Combinator,fix point,总觉得有些对不起大家。但是考虑到这个问题是出了名的累死人不陪命....。这样吧我出一个小题目,看看大家能不能够看懂,如果看得懂的人多呢就讲了,如果少的话就不说了。
def cfold1(fun,z,list);: if(len(list);==0);: return z else: return fun(list.pop();,z,lambda y:cfold1 (fun,y,list);); def cfold(Operator,z,l);: return cfold1(lambda x,t,g:Operator(x,g(t););,z,l); if __name__=="__main__": print cfold(lambda x,y:x+y,0,[1,2,3,4]); 我现在已经能够想象到屏幕前面对这个程序时你的抓狂程度。 为了看懂这个,偶特地去学习了一把python的一些相关的基本语法,比如lambda,比如list.pop(),在纸上画了好一会儿,头发都掉了好几根,推了几步,归纳了一下,答案是4+3+2+1+0吧,要是错了,我真要考虑买块豆腐撞几下了。 |
|
返回顶楼 | |
发表时间:2004-09-17
to:mochow大姐
我和你差不多,为了搞懂这个程序,我不但学习了语法,而且还特地下载了一个python。 我的理解是: print cfold(lambda x,y : x+y,0,[1,2,3,4]) 是交给cfold一个计算任务。 0是初始值 [1,2,3,4]是计算序列 lambda x,y : x+y就是计算的函数。 如果给他的是lambda x,y : x*y 而且初始值得是1 那么得到的就是1*1*2*3*4=24 Trustno1,可以接着讲了吧。 |
|
返回顶楼 | |
发表时间:2004-09-17
把你们的推导过程贴出来吧。
|
|
返回顶楼 | |
发表时间:2004-09-17
Trustno1 写道 把你们的推导过程贴出来吧。
偶这个是土办法 计算cfold(lambda x,y : x+y,0,[1,2,3,4]) 第一步,要弄清lambda x,y : x+y是说啥的,去网上google一把得出 它的意思是 f1=f(x,y)= x+y; 第二步,得出要打印cfold(f1,0,[1,2,3,4]) 第三步,由定义cfold(Operator,z,l)得出 Operator = f1 =f(x,y) = x+y z =0; l = [1,2,3,4] lambda x,t,g:Operator(x,g(t)) 实际上就是f(x,t,g) = x+g(t); 则有: cfold1(lambda x,t,g:Operator(x,g(t)),z,l) = cfold1(x+g(t),0,[1,2,3,4]) 第四步, 开始计算cfold1(x+g(t),0,[1,2,3,4]) 由该函数的定义知 fun的形式为 fun(x,t,g) = x+g(t); list长度不为0,list.pop()为4, lambda y:cfold1 (fun,y,list)则为f(y) = cfold1 (fun,y,[1,2,3]) 则fun(4,0,cfold1 (fun,y,[1,2,3])) = 4+cfold1 (fun,0,[1,2,3]) 第五步,计算4+cfold1 (fun,0,[1,2,3])和第四步差不多,结果是 4+3+cfold1 (fun,0,[1,2]) ... 最后当list为空的时候返回0则结果应该是4+3+2+1+0 |
|
返回顶楼 | |
发表时间:2004-09-17
1、cfold(lambda x,y : x+y,0,[1,2,3,4])
cfold(f(x,y)=x+y,0,[1,2,3,4]) 2、cfold(Operator,z,l) Operator = f(x,y)=x+y z = 0 l = [1,2,3,4] lambda x,t,g : Operator(x,g(t)) = f(x,g,t)=x+g(t) cfold1(lambda x,t,g : Operator(x,g(t)),z,l) cfold1(f(x,g,t)=x+g(t),z,l) 3、cfold1(fun,z,list) fun = f(x,g,t)=x+g(t) z = 0 list = [1,2,3,4] if(len(list)==0): //这是最后一步,在递归的最后 return z //发现数列空了之后,就返回z,也就是初始值 else return fun(list.pop(),z,lambda y:cfold1 (fun,y,list)) 4、fun(list.pop(),z,lambda y:cfold1 (fun,y,list)) fun = x+g(t) x = list.pop() t = z g = f(y)=cfold1 (fun,y,list) 这个函数的含义就是: list.pop()+cfold1(fun,z,list) 5、到这里以后,就可以看清楚一个递归了 cfold1 = fun(list.pop(),z,lambda y:cfold1 (fun,y,list)) fun = x+g(t) g = cfold1 (fun,y,list) //list已经被取走一个数了 6、在回过头去看cfold(Operator,z,l)的作用, 我们给cfold的算法是f(x,y)=x+y 但是cfold需要把他拼装成x+g(y),这样才能实现递归的计算。 我相信自己已经说清楚了。 |
|
返回顶楼 | |
发表时间:2004-09-17
似乎还可以简单点,当得出fun(x,t,g)=x+g(t)的时候,
函数cfold1的返回fun(list.pop(),z,lambda y:cfold1 (fun,y,list)) 可以简化为list.pop()+cfold1 (fun,z,list),就可以看的更清楚了。 |
|
返回顶楼 | |