2006-12-02
Java 函数式编程实验(新添Keyword Message)
关键字: FP Java
实验了以下内容:高阶函数,Currying,Lazy Evaluation,无穷流,Monad。都是很基本的东西。实现也是基于内部类的。没啥是了不起的。只是在给Lazy Evaluation造语法糖的时候,用了一下bytecode动态增强。给Lazy函数的lambda定义内部的所有的局部变量的读取操作前加了Lazy Evaluation过程。
运行结果
calc 1 + 3
4
结果分析:
1、实现了Curry(利用匿名类,绑定参数)
2、实现了Lazy Evaluation(利用载入时字节码修改,会添加进参数是否已经被求值的判断)
3、类型安全
缺点:
匿名类的语法
调用语法(用_表示调用仍然会有很多括号)
12.9:
更新为最新的语法
private final static F<Boolean> TRUE = $(true);
private final static F<Integer> ONE = $(1);
private final static F<Integer> TWO = $(2);
private final static F<Integer> THREE = $(3);
private void demo() {
LF2<Integer, Integer, Integer> add = new LF2<Integer, Integer, Integer>() {
protected Integer lambda(Integer left, Integer right) {
System.out.println("calc " + left + " + " + right);
return left + right;
}
};
LF3<Boolean, Integer, Integer, Integer> select = new LF3<Boolean, Integer, Integer, Integer>() {
protected Integer lambda(Boolean arg1, Integer arg2, Integer arg3) {
if (arg1) {
return arg2;
}
return arg3;
}
};
LF1<Integer, Integer> onePlus = add._(ONE);
F<Integer> onePlusTwo = onePlus._(TWO);
F<Integer> onePlusThree = onePlus._(THREE);
System.out.println(select._(TRUE, onePlusThree, onePlusTwo)._());
}
运行结果
引用
calc 1 + 3
4
结果分析:
1、实现了Curry(利用匿名类,绑定参数)
2、实现了Lazy Evaluation(利用载入时字节码修改,会添加进参数是否已经被求值的判断)
3、类型安全
缺点:
匿名类的语法
调用语法(用_表示调用仍然会有很多括号)
12.9:
更新为最新的语法
评论
cookoo
2006-12-14
Maybe Monad的应用只限于简单的情况:首先如果可选择的情况多于两种(也就是例外情况多于一种)在计算的每一步都要处理这些选择很麻烦,其次这样把正常逻辑和处理违例的逻辑混在一起,不是个best practice。
taowen
2006-12-10
monad应该比你说的还要广一些。按照ajoo的说法,monad是一种计算模型。还有一种更抽象的是arrow啥的。按照我来看就是通过类型系统的限定(由于f的返回值是Maybe Int不是Int了),迫使程序员不能直接拿f的返回值去调用g。必须拿bind来把f和g“绑定”到一起去。不然你不知道该给g传啥参数,因为f的返回值装载Maybe这个“盒子”里呢。由于我认为Maybe是一个泛型的盒子。随意就把Maybe做成了Maybe<T>。
zhangyu8374
2006-12-10
Maybe Monad,谈Monad的入门资料,必定谈它。
首先看代码,比如定义了如下函数:
(1)h 2:正常;
(2)h 0:程序中断,除数不能为0
此时f的返回值,传给g出现了脱节,导致不匹配。此时怎么办,于是想到了搞一个Maybe type construtor,对它们进行统一封装,使得计算可以正常流动起来。就算是除0操作,也被视为了正常,达到了统一 。统一之后,就不会出现计算中断了。
使用用Maybe统一之后的代码:
此时的代码变成了如下的样子:
首先看代码,比如定义了如下函数:
f::Int->Int f x = 10 `div` x g::Int->Int g x = x+1 h = g.f当计算:
(1)h 2:正常;
(2)h 0:程序中断,除数不能为0
此时f的返回值,传给g出现了脱节,导致不匹配。此时怎么办,于是想到了搞一个Maybe type construtor,对它们进行统一封装,使得计算可以正常流动起来。就算是除0操作,也被视为了正常,达到了统一 。统一之后,就不会出现计算中断了。
使用用Maybe统一之后的代码:
f::Int->Maybe Int f x = if x==0 then Nothing else Just (10 `div` x) g::Maybe Int->Maybe Int g Nothing = Nothing g (Just x) = Just (x+1) h = g.f看到上面没有,采用Maybe之后,还是有不爽的地方,就是总是要对Maybe的值进行条件判断,看它是Nothing还是Just。一两个函数组合,问题还不大,当函数多了的时候,就麻烦了,很多的重复代码,那可是bad smell。于是对Maybe类型整了return和>>=两个函数,使其变成Monad,这样一切就好办啦。
此时的代码变成了如下的样子:
f::Int->Maybe Int f x = if x==0 then Nothing else Just (10 `div` x) g::Int->Maybe Int g x = Just (x+1) h x= (Just x)>>=f>>=g这样,在g函数中,就无需再进行判断了,这些工作都交给了Monad。
taowen
2006-12-10
突然发觉curry的写法和keyword message很相近啊。比如说我定义了一个moveFromTo的方法用来把一个元素从一个序列移动到另外一个序列。用keyword message可以写成move aObject :from aList :to anotherList。那么我用Java定义这么一个函数:
可以写成
moveFromTo._(aObject)._(aList)._(anotherList)。显然不是很好看的说。所以祭出cglib来,搞一搞。我希望能够这么写:
所以要定义一下相关的keyword接口:
一般的做法是自己手写每个keyword接口的实现。但是我们已经有一个function啦(moveFromTo)。所以我只要拿cglib根据这个function和传给move的参数(element),就能自动帮我把这几个keyword接口给实现了。写法是:
implement是import static进来的。华丽一点可以做到implement(MoveKeyword.class).accordingTo(moveFromTo).with(element);。
代码在前面的压缩包里。
private F3<String, List<String>, List<String>, Nothing> moveFromTo = new F3<String, List<String>, List<String>, Nothing>() {
public Nothing _(String element, List<String> fromList, List<String> toList) {
fromList.remove(element);
toList.add(element);
return nothing;
}
};
可以写成
moveFromTo._(aObject)._(aList)._(anotherList)。显然不是很好看的说。所以祭出cglib来,搞一搞。我希望能够这么写:
List<String> list1 = list("hello", "hi");
List<String> list2 = list("hi");
move("hello").from(list1).to(list2);
所以要定义一下相关的keyword接口:
private MoveKeyword move(String element) {
return null; //暂时还没实现。
}
public static interface MoveKeyword {
MoveFromKeyword from(List<String> fromList);
}
public static interface MoveFromKeyword {
Nothing to(List<String> toList);
}
一般的做法是自己手写每个keyword接口的实现。但是我们已经有一个function啦(moveFromTo)。所以我只要拿cglib根据这个function和传给move的参数(element),就能自动帮我把这几个keyword接口给实现了。写法是:
return implement(MoveKeyword.class, moveFromTo, element);
implement是import static进来的。华丽一点可以做到implement(MoveKeyword.class).accordingTo(moveFromTo).with(element);。
代码在前面的压缩包里。
taowen
2006-12-09
关于Monad,俺也是现学。发觉拿Java做点函数式实验对于理解函数式语言还是很有帮助的。不过这Monad不知道弄对了没有。我也不是很确定。。。
Maybe Monad,用于减少null checking。只要有一个是null,就停止求值。下面是这个Monad的定义。
这是一个使用的例子。第一行打印nothing to say...第二行打印null
Maybe Monad,用于减少null checking。只要有一个是null,就停止求值。下面是这个Monad的定义。
public abstract class Maybe<T> implements Monad {
public final T value;
private Maybe(T value) {
this.value = value;
}
public static <T1, T2> Maybe<T2> bind(Maybe<T1> m, F1<T1, Maybe<T2>> f) {
return (Maybe<T2>) m.bind(f);
}
public static <T1, T2, T3> Maybe<T3> bind(Maybe<T1> m, F1<T1, Maybe<T2>> f, F1<T2, Maybe<T3>> g) {
return bind(bind(m, f), g);
}
public static <T> Maybe<T> maybe(T value) {
return new Maybe<T>(value) {
};
}
@SuppressWarnings("unchecked")
public Monad bind(F1 f) {
if (value == null) {
return new Maybe(null) {
};
}
return (Monad) f._(value);
}
}
这是一个使用的例子。第一行打印nothing to say...第二行打印null
public class MaybeDemo {
public static void main(String[] args) {
new MaybeDemo().demo();
}
private void demo() {
Maybe<String> result = (Maybe<String>) exec(maybe(""), remark1, remark2);
System.out.println(result.value);
System.out.println(bind(maybe("silence"), remark1, remark2).value);
}
private F1<String, Maybe<String>> remark1 = new F1<String, Maybe<String>>() {
public Maybe<String> _(String words) {
if ("".equals(words)) {
return maybe("be nice, man");
}
return maybe(null);
}
};
private F1<String, Maybe<String>> remark2 = new F1<String, Maybe<String>>() {
public Maybe<String> _(String words) {
return maybe("nothing to say...");
}
};
}
taowen
2006-12-08
添加了LazyStream,支持了无穷序列。下面是一个fibonacci数列的例子。和Haskell的版本没得比,但是俺已经竭尽所能了。cons(element1, fibs._(element2)._$(element1 + element2)),Java的语法能做到这样来表示无穷序列已经不容易了。另外谁能给一个和Haskell版本等价的实现?俺想不出来咋用zipWith等高阶函数来组装出来。貌似语法会更加丑陋。所有的源代码都在附件中。
private void demo() {
LazyStream<Integer> stream = fibs();
for (int i = 0; i < 10; i++) {
System.out.println(stream.current());
stream = stream.rest();
}
}
private static LazyStream<Integer> fibs() {
return fibs._(0, 1);
}
private static F2<Integer, Integer, LazyStream<Integer>> fibs = new F2<Integer, Integer, LazyStream<Integer>>() {
public LazyStream<Integer> _(Integer element1, Integer element2) {
return cons(element1, fibs._(element2)._$(element1 + element2));
}
};
taowen
2006-12-06
SICP练习题4.25。定义了一个$函数把值封装成对象。定义了unless来做判断。定义了mul来做乘法。最后是把这些组装起来变成一个求阶乘的函数。如果这个函数不是lazy的话,必然导致堆栈溢出。
private static LF1<Integer, Integer> factorial = new LF1<Integer, Integer>() {
protected Integer lambda(Integer n) {
F<Integer> val1 = mul._($(n))._(factorial._($(n - 1)));
F<Integer> val2 = $(1);
return unless._($(n == 1))._(val1)._(val2)._();
}
};
- 浏览: 81558 次
- 性别:

- 来自: 北京

- 详细资料
搜索本博客
我的相册
step2
共 6 张
共 6 张
最近加入圈子
最新评论
-
汉语编程,有搞头
就E语言算巴 没用过也没计划用 CHTML不错哈哈
-- by lwwin -
关于estimation的闲言碎语
1. BA是Business Analyst的缩写,就是写story的人.2. ...
-- by taowen -
关于estimation的闲言碎语
请教:1.BA是什么意思?Business Analyzer?2.“好的esti ...
-- by movingboy -
计划经济体制的CMM,市场 ...
有创意,有启发性。顶!!
-- by estest -
贫血的Domain Model
看了这么久的领域模型,争论的真是没完没了。 难道就不能跳开这个领域模型或者还领域 ...
-- by hunter001201






评论排行榜