使用Java实现haskell-style的list
作为一个haskell这门函数式编程语言的爱好者,我特别喜欢它的list操作和推导功能。与传统面向对象或者过程语言不同的是,函数式语言通常喜欢把它们分为head、tail或者init、last等两部分,而不是一个数组性的列表。
针对列表的操作,也通常使用递归和迭代的方式来完成,特别强大。java8后,有了stream之后,才感觉能够和它有得一拼,但总感觉stream操作的list比较繁琐。
工作之余,做为一种爱好或者锻炼,我自己用java实现了一套haskell-style的list类,支持大部分原生haskell list函数和操作,并且可以与java list(准确来说是迭代器)进行相互转换。
得到一个haskell-style列表,你仅仅需要像这样:
PreludeList<Integer> intList = PreludeList.of(1,2,3,4);
你还可以像下面这样,得到一个无限长的列表:
PreludeList<Integer> rangeList = PreludeList.range(1, 10000);
PreludeList<Integer> repeatList = PreludeList.repeat(3);
PreludeList<Integer> cycleList = PreludeList.cycle(Preludelist.of(1,3,5));
PreludeList<Integer> iterableList = PreludeList.iterable(t -> t * 3, 3); //[3, 9, 27, 81....]
并且,这些全部都是惰性求值,真正用的时候才会去延迟计算。
你还可以进行更多的list操作:
PreludeList<Integer> intList = PreludeList.of(1,2,3,4,5,6);
//基础操作
Integer headValue = PreludeList.head(intList);
PreludeList<Integer> tailList = PreludeList.tail(intList);
PreludeList<Integer> initList = PreludeList.init(intList);
Integer lastValue = PreludeList.last(intList);
//列表操作
PreludeList<Integer> revertList = PreludeList.reverse(intList); //一个反转的整数列表
PreludeList<Integer> take3List = PreludeList.take(3, intList); //取前面三项组成一个新的列表
PreludeList<Integer> drop3List = PreludeList.drop(3, intList); //移除掉前面三项组成的新列表
PreludeList<Integer> filterList = PreludeList.filter(t -> t % 2 == 0, intList); //取偶数组成新列表
PreludeList<Integer> mapList = PreludeList.map(t -> t * 2, intList); //每个数增长到2倍的新列表
//与Java迭代器的互动
Iterable iterable = PreludeList.to(intList);
PreludeList<Integer> iterableList = PreludeList.from(iterable);
//其他
System.out.println(intList.toString()); //它会输出[1,2,3,4,5,6]
说了这么多,有没有点期待,完整的功能比上面更丰富,还在不断完善中。。。。。
代码见下:
import javax.swing.text.html.HTMLDocument;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Iterator;
import java.util.function.Function;
import java.util.function.Predicate;
/**
*
* @author richardyang
* @version $Id: PreludeList.java, v 0.1 2018年06月01日 下午5:10 richardyang Exp $
*/
public class PreludeList<T> {
private static class Nil<T> extends PreludeList<T> {
@Override
protected T getHead() {
throw new UnsupportedOperationException("Prelude list empty");
}
@Override
protected PreludeList<T> getTail() {
throw new UnsupportedOperationException("Prelude list empty");
}
}
private static class RepeatList<T> extends PreludeList<T> {
private T x;
protected RepeatList(T x) {
this.isEmpty = false;
this.x = x;
}
@Override
protected T getHead() {
return x;
}
@Override
protected PreludeList<T> getTail() {
return new RepeatList(x);
}
}
private static class CycleList<T> extends PreludeList<T> {
private PreludeList<T> cycleList;
protected CycleList(PreludeList<T> list) {
this.cycleList = list;
this.isEmpty = false;
}
@Override
protected T getHead() {
return cycleList.getHead();
}
@Override
protected PreludeList<T> getTail() {
if (!nil(cycleList.getTail())) {
PreludeList<T> tailList = cycleList.getTail();
return PreludeList.cons(tailList, new CycleList<T>(cycleList));
}
return new RepeatList<T>(head(cycleList));
}
}
private static class IterateList<T> extends PreludeList<T> {
private Function<T, T> function;
private T x;
protected IterateList(Function<T, T> function, T x) {
this.function = function;
this.x = x;
this.isEmpty = false;
}
@Override
protected T getHead() {
return x;
}
@Override
protected PreludeList<T> getTail() {
return new IterateList<T>(function, function.apply(x));
}
}
private static class RangeList<T extends Number> extends PreludeList<T> {
private T start;
private T stop;
private T step;
private int stepCount;
protected RangeList(T start, T stop, T step, int stepCount) {
this.start = start;
this.stop = stop;
this.step = step;
this.stepCount = stepCount;
this.isEmpty = false;
}
@Override
protected T getHead() {
try {
Number result = NumberFormat.getInstance().parse(String.valueOf(start.doubleValue() + step.doubleValue() * stepCount));
return (T)result;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
@Override
protected PreludeList<T> getTail() {
if (canNext()) {
return new RangeList<T>(start, stop, step, stepCount + 1);
}
return nilElem;
}
private boolean canNext() {
boolean lt = step.doubleValue() > 0;
return lt
? start.doubleValue() + step.doubleValue() * (stepCount + 1) <= stop.doubleValue()
: start.doubleValue() + step.doubleValue() * (stepCount + 1) >= stop.doubleValue();
}
}
private static class IteratorList<T> extends PreludeList<T> {
private Iterable<T> iterable;
private T headValue;
protected IteratorList(Iterable<T> iterable) {
this.iterable = iterable;
this.isEmpty = !iterable.iterator().hasNext();
if (!this.isEmpty) {
this.headValue = iterable.iterator().next();
}
}
@Override
protected T getHead() {
if (!isEmpty) {
return headValue;
}
throw new UnsupportedOperationException("Prelude Iterator empty");
}
@Override
protected PreludeList<T> getTail() {
if (!isEmpty) {
return new IteratorList<T>(new Iterable<T>() {
@Override
public Iterator<T> iterator() {
Iterator<T> iterator = iterable.iterator();
iterator.next();
return iterator;
}
});
}
return nilElem;
}
}
private static class PreludeIterator<T> implements Iterator<T> {
private PreludeList<T> list;
protected PreludeIterator(PreludeList<T> list) {
this.list = list;
}
@Override
public boolean hasNext() {
return !PreludeList.nil(list);
}
@Override
public T next() {
T result = list.getHead();
list = list.getTail();
return result;
}
}
private T headItem;
private PreludeList<T> tailList;
protected boolean isEmpty = true;
private static Nil nilElem = new Nil<>();
protected T getHead() {
return headItem;
}
protected PreludeList<T> getTail() {
return tailList;
}
private PreludeList() {}
private PreludeList(T elem) {
this.headItem = elem;
this.tailList = nilElem;
this.isEmpty = false;
}
private PreludeList(T elem, PreludeList<T> tailList) {
this.headItem = elem;
this.tailList = tailList;
this.isEmpty = false;
}
public static <T> PreludeList<T> of(T ...elem) {
if (elem.length > 0) {
T _head = elem[0];
PreludeList<T> p = null;
for (int i = elem.length - 1; i > 0; --i) {
if (p != null) {
p = new PreludeList<T>(elem[i], p);
} else {
p = new PreludeList<T>(elem[i]);
}
}
return new PreludeList<T>(_head, p);
}
return nilElem;
}
public static <T extends Number> PreludeList<T> range(T start, T stop, T step) {
return new RangeList<T>(start, stop, step, 0);
}
public static <T> PreludeList<T> from(Iterable<T> iterable) {
if (iterable != null) {
return new IteratorList<T>(iterable);
}
throw new UnsupportedOperationException("iterable is null");
}
public static <T> Iterable<T> to(PreludeList<T> list) {
return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return new PreludeIterator<T>(list);
}
};
}
public static <T> PreludeList<T> empty() {
return nilElem;
}
public static <T> boolean nil(PreludeList<T> list) {
return list == null || list.isEmpty || list == nilElem;
}
public static <T> PreludeList<T> cons(T elem, PreludeList<T> list) {
if (elem == nilElem) {
return list;
}
if (list == nilElem) {
return new PreludeList<>(elem);
}
return new PreludeList<>(elem, list);
}
public static <T> PreludeList<T> cons(PreludeList<T> list, T elem) {
if (elem == nilElem) {
return list;
}
if (list == nilElem) {
return new PreludeList<>(elem);
}
return PreludeList.cons(list, new PreludeList<T>(elem));
}
public static <T> PreludeList<T> cons(PreludeList<T> list1, PreludeList<T> list2) {
if (list1 == nilElem) {
return list2;
}
if (list2 == nilElem) {
return list1;
}
return new PreludeList<T>(list1.getHead(), cons(list1.getTail(), list2));
}
public static <T> T head(PreludeList<T> list) {
if (!nil(list)) {
return list.getHead();
}
throw new UnsupportedOperationException("Prelude list empty");
}
public static <T> PreludeList<T> tail(PreludeList<T> list) {
if (!nil(list)) {
return list.getTail();
}
throw new UnsupportedOperationException("Prelude list empty");
}
public static <T> PreludeList<T> init(PreludeList<T> list) {
T t = head(list);
if (nil(list.getTail())) {
return nilElem;
}
return new PreludeList<>(t, init(list.getTail()));
}
public static <T> T last(PreludeList<T> list) {
T t = head(list);
if (nil(list.getTail())) {
return t;
}
return last(list.getTail());
}
public static <T> long length(PreludeList<T> list) {
if (nil(list)) {
return 0;
}
return 1 + length(list.getTail());
}
public static <T> T get(int pos, PreludeList<T> list) {
if (pos < 0) {
throw new IllegalArgumentException("pos is negative");
}
if (nil(list)) {
throw new UnsupportedOperationException("prelude list is empty");
}
if (pos == 0) {
return head(list);
}
return get(pos - 1, tail(list));
}
public static <T> PreludeList<T> repeat(T x) {
if (x == nilElem) {
throw new UnsupportedOperationException("The repeat operation doesn't support empty list");
}
return new RepeatList<T>(x);
}
public static <T> PreludeList<T> replicate(long count, T x) {
if (x == nilElem) {
throw new UnsupportedOperationException("The repeat operation doesn't support empty list");
}
return take(count, repeat(x));
}
public static <T> PreludeList<T> reverse(PreludeList<T> list) {
if (nil(list)) {
return nilElem;
}
return cons(reverse(list.getTail()), new PreludeList<T>(list.getHead()));
}
public static <T> PreludeList<T> take(long count, PreludeList<T> list) {
if (count <= 0 || list.isEmpty) {
return nilElem;
}
return new PreludeList<T>(list.getHead(), take(count -1, list.getTail()));
}
public static <T> PreludeList<T> drop(long count, PreludeList<T> list) {
if (count <= 0 || list.isEmpty) {
return list;
}
return drop(count - 1, list.getTail());
}
public static <T> PreludeList<T> cycle(PreludeList<T> list) {
if (list == nilElem) {
throw new UnsupportedOperationException("The repeat operation doesn't support empty list");
}
return new CycleList<T>(list);
}
public static <T> PreludeList<T> iterate(Function<T, T> function, T x) {
return new IterateList<T>(function, x);
}
public static <T, R> PreludeList<R> map(Function<T, R> function, PreludeList<T> list) {
if (nil(list)) {
return nilElem;
}
return new PreludeList<R>(function.apply(head(list)), map(function, list.getTail()));
}
public static <T> PreludeList<T> filter(Predicate<T> predicate, PreludeList<T> list) {
if (nil(list)) {
return list;
}
if (!predicate.test(head(list))) {
return filter(predicate, list.getTail());
} else {
return new PreludeList<>(head(list), filter(predicate, list.getTail()));
}
}
public static <T, R> PreludeList<R> flatMap(Function<T, PreludeList<R>> function, PreludeList<T> list) {
if (nil(list)) {
return nilElem;
}
return PreludeList.cons(function.apply(head(list)), flatMap(function, list.getTail()));
}
public static <T> PreludeList<PreludeList<T>> splitAt(int count, PreludeList<T> list) {
if (nil(list)) {
return nilElem;
}
return new PreludeList<PreludeList<T>>(take(count, list), splitAt(count, drop(count, list)));
}
public static <T> PreludeList<PreludeList<T>> splitAt(Predicate<T> predicate, PreludeList<T> list) {
if (nil(list)) {
return nilElem;
}
PreludeList<T> elem = PreludeList.nilElem;
PreludeList<T> loopList = list;
while (!nil(loopList)) {
T headItem = head(loopList);
elem = PreludeList.cons(elem, new PreludeList<T>(headItem));
if (!predicate.test(headItem)) {
loopList = tail(loopList);
} else {
break;
}
}
return !nil(loopList) ? PreludeList.cons(elem, splitAt(predicate, tail(loopList))) : new PreludeList<PreludeList<T>>(elem);
}
private static <T> int elemIndex(T x, PreludeList<T> list, int pos) {
if (nil(list)) {
return -1;
}
T t = head(list);
if (t.equals(x) || t == x) {
return pos;
}
return elemIndex(x, tail(list), pos + 1);
}
public static <T> int elemIndex(T x, PreludeList<T> list) {
return elemIndex(x, tail(list), 0);
}
private static <T> PreludeList<Integer> elemIndices(T x, PreludeList<T> list, int pos) {
if (nil(list)) {
return nilElem;
}
T t = head(list);
return t.equals(x) || t == x ? PreludeList.cons(pos, elemIndices(x, tail(list), pos + 1)) : elemIndices(x, tail(list), pos + 1);
}
public static <T> PreludeList<Integer> elemIndices(T x, PreludeList<T> list) {
return elemIndices(x, tail(list), 0);
}
private static <T> T find(Predicate<T> predicate, PreludeList<T> list) {
if (nil(list)) {
throw new IllegalArgumentException("Can't find value");
}
T t = head(list);
if (predicate.test(t)) {
return t;
}
return find(predicate, tail(list));
}
private static <T> int findIndex(Predicate<T> predicate, PreludeList<T> list, int pos) {
if (nil(list)) {
return -1;
}
T t = head(list);
if (predicate.test(t)) {
return pos;
}
return findIndex(predicate, tail(list), pos + 1);
}
public static <T> int findIndex(Predicate<T> predicate, PreludeList<T> list) {
return findIndex(predicate, tail(list), 0);
}
private static <T> PreludeList<Integer> findIndices(Predicate<T> predicate, PreludeList<T> list, int pos) {
if (nil(list)) {
return nilElem;
}
T t = head(list);
return predicate.test(t) ? PreludeList.cons(pos, findIndices(predicate, tail(list), pos + 1)) : findIndices(predicate, tail(list), pos + 1);
}
public static <T> PreludeList<Integer> findIndices(Predicate<T> predicate, PreludeList<T> list) {
return findIndices(predicate, tail(list), 0);
}
//partition even [2,4,6,7,9,10,11] ==> ([2,4,6,10],[7,9,11])
public static <T> PreludeList<PreludeList<T>> partition(Predicate<T> predicate, PreludeList<T> list) {
if (nil(list)) {
return nilElem;
}
return PreludeList.cons(new PreludeList<PreludeList<T>>(filter(predicate, list)), new PreludeList<PreludeList<T>>(filter(predicate.negate(), list)));
}
@Override
public String toString() {
if (isEmpty) {
return "[]";
}
StringBuilder stringBuilder = new StringBuilder("[");
PreludeList<T> list = this;
while (!list.isEmpty) {
T t = list.getHead();
stringBuilder.append(t.toString());
try {
list = list.getTail();
if (!list.isEmpty) {
stringBuilder.append(",");
}
} catch (UnsupportedOperationException e) {
break;
}
}
stringBuilder.append("]");
return stringBuilder.toString();
}
}
使用Java实现haskell-style的list的更多相关文章
- java之google style
Google的Java编码规范英文版: http://google-styleguide.googlecode.com/svn/trunk/javaguide.html Google的Java编码规范 ...
- JAVA开发CHECK STYLE
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE module PUBLIC "-/ ...
- java 去掉html/style/css等标签
//定义script的正则表达式 private static String regEx_script="<script[^>]*?>[\\s\\S]*?<\\/sc ...
- 在IntelliJ IDEA中配置Google Java Code Style及代码格式化快捷键
google-java-format plugin should intercept the “Reformat Code” action in IDEA (Ctrl+Alt+L) and apply ...
- [JAVA] 一个可以编辑、编译、运行Java简单文件的记事本java实现
本来是Java课做一个仿windows记事本的实验,后来突然脑子一热,结果就给它加了一个编译运行Java文件的功能. 本工程总共大约3000行代码,基本上把所学的java界面.文件.控件的功能都包含在 ...
- Android网络传输中必用的两个加密算法:MD5 和 RSA (附java完成测试代码)
MD5和RSA是网络传输中最常用的两个算法,了解这两个算法原理后就能大致知道加密是怎么一回事了.但这两种算法使用环境有差异,刚好互补. 一.MD5算法 首先MD5是不可逆的,只能加密而不能解密.比如明 ...
- 【总结】java命令解析以及编译器,虚拟机如何定位类
学Java有些日子了,一直都使用IDE来写程序.这样的好处就是能让我连如何用命令行编译,解释执行Java源代码都不知道,就更不清楚JDK中的编译器和虚拟机(包含字节码解释器)是如何定位到类文件的.悲哀 ...
- Java开发常用代码
1. 字符串有整型的相互转换 String a = String.valueOf(2); //integer to numeric string int i = Integer.parseInt(a) ...
- java.util.logging.Logger基础教程
从JDK1.4开始即引入与日志相关的类java.util.logging.Logger,但由于Log4J的存在,一直未能广泛使用.综合网上各类说法,大致认为: (1)Logger:适用于小型系统,当日 ...
- JAVA设计模式(09):结构化-代理模式(Proxy)
一,定义: 代理模式(Proxy):为其它对象提供一种代理以控制对这个对象的訪问. 二.其类图: 三,分类一:静态代理 1,介绍:也就是须要我们为目标对象编写一个代理对象,在编译期就生成了这个代理对 ...
随机推荐
- TechEmpower 21轮Web框架 性能评测 -- C# 的性能 和 Rust、C++并驾齐驱
自从2021年2月第20轮公布的测试以后,一年半后 的2022年7月19日 发布了 TechEmpower 21轮测试报告:Round 21 results - TechEmpower Framewo ...
- 从-99打造Sentinel高可用集群限流中间件
接上篇Sentinel集群限流探索,上次简单提到了集群限流的原理,然后用官方给的 demo 简单修改了一下,可以正常运行生效. 这一次需要更进一步,基于 Sentinel 实现内嵌式集群限流的高可用方 ...
- 并发编程原理学习-reentrantlock源码分析
ReentrantLock基本概念 ReentrantLock是一个可重入锁,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁,并且在获取锁时支持选择公平模式或者非公平模式 ...
- 解决zlibrary注册后,再次登录提示密码错误的问题
很多小伙伴注册后,再登录提示电子邮件或密码错误,但是可以确认账号密码都是正确的,这种应该怎么处理呢? 其实这种问题有两种处理方式, 首先使用 https://find.looks.wang/ 检测可以 ...
- 在.NET 6.0中使用不同的托管模型
大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本章是<定制ASP NET 6.0框架系列文章>的第六篇.在本章中,我 ...
- Python小游戏——外星人入侵(保姆级教程)第一章 05重构模块game_functions
系列文章目录 第一章:武装飞船 05:重构:模块game_functions 一.重构 在大型项目中,经常需要在添加新代码前重构既有代码.重构旨在简化既有代码的结构,使其更容易扩展.在本节中,我们将创 ...
- 文心大模型api使用
文心大模型api使用 首先,我们要获取硅谷社区的连个key 复制两个api备用 获取Access Token 获取access_token示例代码 之后就会输出 作文创作 作文创作:作文创作接口基于文 ...
- Springboot连接数据库 (解决报错)
好家伙,来解决报错 1.新建项目时, 将SQL的" Spring Date 'jdbc' "点上 2.使用idea快速创建springboot项目时会出现连接不到服务器的情况 这里 ...
- Ubuntu locale设置
/bin/bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8) 解决方法: 1 sudo locale-gen &q ...
- 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(中)
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 四.创建一个Blazor应用程序 1. 第一种创 ...