`
taowen
  • 浏览: 193826 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java 函数式编程实验(新添Keyword Message)

阅读更多
实验了以下内容:高阶函数,Currying,Lazy Evaluation,无穷流,Monad。都是很基本的东西。实现也是基于内部类的。没啥是了不起的。只是在给Lazy Evaluation造语法糖的时候,用了一下bytecode动态增强。给Lazy函数的lambda定义内部的所有的局部变量的读取操作前加了Lazy Evaluation过程。

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:
更新为最新的语法
分享到:
评论
7 楼 cookoo 2006-12-14  
Maybe Monad的应用只限于简单的情况:首先如果可选择的情况多于两种(也就是例外情况多于一种)在计算的每一步都要处理这些选择很麻烦,其次这样把正常逻辑和处理违例的逻辑混在一起,不是个best practice。
6 楼 taowen 2006-12-10  
monad应该比你说的还要广一些。按照ajoo的说法,monad是一种计算模型。还有一种更抽象的是arrow啥的。按照我来看就是通过类型系统的限定(由于f的返回值是Maybe Int不是Int了),迫使程序员不能直接拿f的返回值去调用g。必须拿bind来把f和g“绑定”到一起去。不然你不知道该给g传啥参数,因为f的返回值装载Maybe这个“盒子”里呢。由于我认为Maybe是一个泛型的盒子。随意就把Maybe做成了Maybe<T>。
5 楼 zhangyu8374 2006-12-10  
Maybe Monad,谈Monad的入门资料,必定谈它。

首先看代码,比如定义了如下函数:
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。
4 楼 taowen 2006-12-10  
突然发觉curry的写法和keyword message很相近啊。比如说我定义了一个moveFromTo的方法用来把一个元素从一个序列移动到另外一个序列。用keyword message可以写成move aObject :from aList :to anotherList。那么我用Java定义这么一个函数:
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);。
代码在前面的压缩包里。
3 楼 taowen 2006-12-09  
关于Monad,俺也是现学。发觉拿Java做点函数式实验对于理解函数式语言还是很有帮助的。不过这Monad不知道弄对了没有。我也不是很确定。。。
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...");
		}
	};
}
2 楼 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));
	}
};
1 楼 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)._();
	}
};

相关推荐

    Java基础之Java编程基础

    Java中有一组预定义的保留字,它们被称为关键字(keyword),具有特殊含义并用于特定的编程目的。所有的Java关键字都是小写的,像"true"、"false"和"null"虽不是关键字,但也不允许用作标识符。此外,Java保留了几...

    search_keyword12.rar_Java关键字

    Java关键字是编程的基础,它们是Java语言预定义的标识符,具有特定的含义和功能,不能用作变量名、方法名或类名。在Java中,关键字是保留给编译器使用的,它们对于理解程序的结构和控制流程至关重要。本文将深入探讨...

    Java编程常用单词.pdf

    Java编程语言是面向对象编程(OOP)的一种重要实现,其核心概念包括类(Class)、对象(Object)、继承(Inheritance)和多态性(Polymorphism)。在Java中,类是创建对象的模板,它定义了对象的属性(Attribute)和...

    java实现根据关键字查找所在文件夹的文件

    在Java编程语言中,实现根据关键字查找文件夹内包含该关键字的文件是一项常见的任务,尤其在数据处理、日志分析或者文件管理系统中。这个功能可以帮助用户快速定位到含有特定信息的文件,提高工作效率。以下是一个...

    java实验报告——对象和类.docx

    【Java实验报告——对象和类】的实验内容主要围绕面向对象编程的核心概念展开,通过设计并实现一个“广石化院电信学院学生通信录”系统,深入理解和应用Java中的类和对象。以下是实验涉及的主要知识点: 1. **面向...

    keyword.other.package.java

    keyword.other.package.java

    java读取csv例子

    Java读取CSV例子 Java读取CSV例子是通过使用javacsv-2.0.jar包来实现的。javacsv-2.0.jar包提供了CsvReader和CsvWriter两个类,分别用于读取和写入CSV文件。在本例子中,我们将展示如何使用javacsv-2.0.jar包来...

    java核心编程详细笔记

    Java是一种广泛使用的面向对象的编程语言,其核心编程包括了类、对象、方法等概念。以下是对标题和描述中提到的一些关键知识点的详细说明: 1. **访问修饰符**: - `public`:公共访问修饰符,允许任何类访问该类...

    JAVA开源关键词提取框架

    【JAVA开源关键词提取框架】是Java编程语言中用于文本处理和信息检索的一种工具,它能够帮助开发者从大量文本数据中自动识别出最具代表性的关键词。关键词提取是自然语言处理(NLP)领域的一个重要组成部分,广泛...

    Keyword_Scraper_-_by_xRisky_keyword_

    《关键词抓取工具——xRisky的Keyword Scraper解析》 在互联网营销和搜索引擎优化(SEO)领域,关键词是至关重要的元素。它们是连接用户搜索意图与网站内容的桥梁,有效的关键词策略能帮助网站获得更高的曝光率和...

    将java代码生成html并且高亮显示的类

    Java是一种面向对象的编程语言,用于开发跨平台的应用程序,其代码通常保存在`.java`文件中。而HTML(超文本标记语言)是用于创建网页的标准标记语言,它包含一系列标签来定义网页结构和内容。 要将Java代码转换为...

    KeyWordDemo.java

    还有很多java基础视频,按这个学习会有很多收获,还有代码,作业。

    java专业英语词汇-基础篇

    在了解Java编程语言的过程中,掌握相关的专业英语词汇是不可或缺的一步。这些词汇涉及计算机基础、Java语言核心概念、编程原理以及面向对象设计等多个方面。下面将详细列出并解释这些基础知识点,帮助理解Java专业...

    KWIC-各种风格-JAVA

    标题“KWIC-各种风格-JAVA”所指的是一种基于JAVA编程语言的特定技术或实践,其中“KWIC”可能是“Keyword-In-Context”的缩写,通常用于信息检索和文本分析,将关键词放在上下文中展示。这个压缩包可能包含了几种...

    java必记单词

    ### Java 必记单词解析 #### AbstractWindowToolkit (AWT) 抽象窗口工具包 - **定义**:AWT 是 Java 提供的一组用于创建图形用户界面 (GUI) 的类库,它允许开发者创建独立于操作系统的窗口、按钮、菜单等控件。 - *...

    Java 关键字定位位置

    在Java编程中,关键字定位位置是一项重要的技能,特别是在处理PDF文档时。PDF(Portable Document Format)文件格式广泛用于存储和共享文档,而Java提供了一系列工具和技术来解析和操作这种文件。在这个场景中,我们...

    java利用DFA算法实现敏感词过滤功能

    在本文中,我们将探讨如何使用DFA(有穷自动机)算法在Java中实现敏感词过滤功能。敏感词过滤在许多应用程序中都是必要的,例如社交媒体、论坛或博客平台,以防止用户发布不当或有害的内容。以下是对DFA算法及其在...

    java工程师笔试题.pdf

    根据提供的文件部分内容,我们可以提炼出一系列Java相关的知识点,以及一些编程基础概念,如下: 1. Java编程语言基础 - Java类和对象:包括类(class)的定义,构造器(constructor)的使用,以及Java中类的实例...

    java代码文件转HTML

    1. **Java编程基础**:Java是多用途、面向对象的编程语言,它提供了丰富的库和API,可以用来读取文件、处理字符串、执行正则表达式操作等。在这个项目中,我们可能需要使用`java.io`包下的`BufferedReader`和`...

Global site tag (gtag.js) - Google Analytics