Hướng dẫn lập trình hàm với Functional Java

Giới thiệu Functional Java

Functional Java là một thư viện dành cho ngôn ngữ Java, cho phép triển khai lập trình hàm. Thư viện này có giao diện rất giống với ngôn ngữ Haskell, với nhiều tên phương thức được lấy trực tiếp từ ngôn ngữ này.

<!-- https://mvnrepository.com/artifact/org.functionaljava/functionaljava -->
<dependency>
    <groupId>org.functionaljava</groupId>
    <artifactId>functionaljava</artifactId>
    <version>4.7</version>
</dependency>

Functional Java so với Java 8

Java 8 tiêu chuẩn cũng đã giới thiệu nhiều yếu tố của lập trình hàm như Stream, lambda và các giao diện hàm. Tuy nhiên, về mặt chức năng, Java 8 còn kém xa Functional Java và cũng có những hạn chế nhất định.

Các giao diện hàm

F0, F, F2, ..., F8

Đây là các giao diện hàm có giá trị trả về. Để sử dụng các giao diện này, cần gọi phương thức f. F0 không có tham số, F có 1 tham số, F2 có 2 tham số, ..., F8 có 8 tham số. F0 có 1 tham số kiểu, F có 2 tham số kiểu, F2 có 3 tham số kiểu, ..., F8 có 9 tham số kiểu. Tham số kiểu cuối cùng đại diện cho kiểu giá trị trả về. Ví dụ: F<Integer, Boolean> có tham số kiểu là Integer và giá trị trả về là Boolean.

import fj.F;
import fj.F2;
import fj.F3;
F<Integer, Integer> doubleValue = num -> num * 2;
F2<Integer, Integer, Integer> add = (x, y) -> x + y;
F3<Integer, Integer, Integer, Integer> sum = (x, y, z) -> x + y + z;
System.out.println(doubleValue.f(6), add.f(6, 7), sum.f(3, 4, 5)); // 12 13 12

Effect0, Effect1, Effect2, ..., Effect8

Đây là các giao diện hàm không có giá trị trả về. Để sử dụng các giao diện này, cần gọi phương thức f. Effect0 không có tham số, Effect1 có 1 tham số, Effect2 có 2 tham số, ..., Effect8 có 8 tham số. Ví dụ: Effect1<Integer> có tham số kiểu là Integer và giá trị trả về là void.

import fj.function.Effect1;
Effect1<Integer> display = number -> System.out.println(number);
display.f(333);  // 333

Try0, Try1, Try2, ..., Try8

Đây là các giao diện hàm có xử lý ngoại lệ và có giá trị trả về. Để sử dụng các giao diện này, cần gọi phương thức f. Try0 không có tham số, Try1 có 1 tham số, Try2 có 2 tham số, ..., Try8 có 8 tham số. Try0 có 2 tham số kiểu, Try1 có 3 tham số kiểu, Try2 có 4 tham số kiểu, ..., Try8 có 10 tham số kiểu. Hai tham số kiểu cuối cùng đại diện cho kiểu giá trị trả về và kiểu ngoại lệ. Ví dụ: Try1<Integer, Boolean, Exception> có tham số kiểu là Integer, giá trị trả về là Boolean, và ngoại lệ là Exception.

TryEffect0, TryEffect1, TryEffect2, ..., TryEffect8

Đây là các giao diện hàm có xử lý ngoại lệ nhưng không có giá trị trả về. Để sử dụng các giao diện này, cần gọi phương thức f. TryEffect0 không có tham số, TryEffect1 có 1 tham số, TryEffect2 có 2 tham số, ..., TryEffect8 có 8 tham số. TryEffect0 có 1 tham số kiểu, TryEffect1 có 2 tham số kiểu, TryEffect2 có 3 tham số kiểu, ..., TryEffect8 có 9 tham số kiểu. Tham số kiểu cuối cùng đại diện cho kiểu ngoại lệ. Ví dụ: TryEffect1<Integer, Exception> có tham số kiểu là Integer, giá trị trả về là void, và ngoại lệ là Exception.

Primitive

Cung cấp các dạng viết tắt của giao diện hàm F để chuyển đổi giữa các kiểu dữ liệu nguyên thủy.

import static fj.data.Array.array;
import static fj.Primitive.Integer_Double;
double value = Integer_Double.f(1);
// value = (double)1;
Double[] values = array(1, 2, 3).map(Integer_Double).array(Double[].class);

Bảng so sánh giao diện hàm (Functional Java và Java 8)

Giao diện FJ Phương thức FJ Giao diện Java 8 Phương thức Java 8
Effect2<T, U> f BiConsumer<T, U> accept
F2<T, U, R> f BiFunction<T, U, R> apply
F2<T, T, T> f BinaryOperator<T> apply
F2<T, U, Boolean> f BiPredicate<T, U> test
F0<Boolean> f BooleanSupplier getAsBoolean

Kiểu dữ liệu tổ hợp

P1, P2, ..., P8, P

Kiểu tích (Product) (kiểu dữ liệu tổ hợp với các thành phần có kiểu khác nhau). Gọi phương thức _1, _2, ..., _8 của giao diện để đọc các thành phần của tổ hợp. P1 chỉ có 1 thành phần, P2 có 2 thành phần, ..., P8 có 8 thành phần. Để xây dựng tổ hợp, cần gọi phương thức p của lớp P và các phương thức p1, p2, ..., p8.

import fj.P;
import fj.P2;
P2<Integer, String> pair = P.p(1, "a");
System.out.println(pair);  // (1,a)
pair = P.<Integer, String>p2().f(2).f("b");
System.out.println(pair);  // (2,b)

V2, ..., V8, V

Kiểu vector (kiểu dữ liệu tổ hợp với các thành phần có kiểu giống nhau). Gọi phương thức _1, _2, ..., _8 của giao diện để đọc các thành phần của tổ hợp. V2 có 2 thành phần, ..., V8 có 8 thành phần. Để xây dựng tổ hợp, cần gọi phương thức v của lớp V và các phương thức v2, ..., v8.

import fj.data.vector.V;
import fj.data.vector.V2;
V2<Integer> vector2 = V.v(1, 3);
System.out.println(vector2.p());  // (1,3)
vector2 = V.<Integer>v2().f(2, 4);
System.out.println(vector2.p());  // (2,4)

Cấu trúc dữ liệu

List

package fp;

import fj.Equal;
import fj.Ord;
import fj.Ordering;
import fj.P;
import fj.data.List;
import fj.data.Option;

import static fj.Equal.intEqual;
import static fj.Ord.intOrd;
import static fj.data.List.list;

public class FJList {

	static void display(Object o) { System.out.println(o); }
	public static void main(String[] args) {
		display(list(1, 1, 1).allEqual(intEqual)); // true
		display(list(1, 2).append(list(3))); // List(1,2,3)
		display(list(1, 2, 3).apply(list(i -> i + 3, i -> i * 2))); // List(4,5,6,2,4,6)
		Integer[] arr = list(1, 2, 3).array(Integer[].class); // 123
		display(List.asString(list('a', 'b', 'c'))); // abc
		display(list(1, 2, 3).bind(i -> list(i, i * 2))); // List(1,2,2,4,3,6)
		display(list(1, 2, 3).bind(list(4, 5, 6), x -> y -> x * y)); // List(4,5,6,8,10,12,12,15,18)
		display(list(1, 2, 3).bind(list(4, 5, 6), (x, y) -> x * y)); // List(4,5,6,8,10,12,12,15,18)
		// takeUntil + dropUntil
		display(list(1, 2, 3).breakk(i -> i % 2 == 0)); // (List(1),List(2,3))
		display(List.cons(3, list(1, 2))); // List(3,1,2)
		display(list(1, 2).cons(3)); // List(3,1,2)
		display(list(1, 2, 3).delete(2, intEqual)); // List(1,3)
		display(list(1, 2, 3, 4, 5).drop(2)); // List(3,4,5)
		display(list(1, 2, 3, 4, 5).dropWhile(i -> i < 3)); // List(3,4,5)
		display(list(1, 2, 3, 4, 5).elementIndex(intEqual, 3)); // Some(2)
		display(list(1, 2, 3, 4, 5).exists(i -> i % 3 == 1)); // true
		display(list(1, 2, 3, 4, 5).filter(i -> i % 2 == 1)); // List(1,3,5)
		display(list(1, 2, 3, 4, 5).find(i -> i / 3 == 1)); // Some(3)
		display(list(1, 2, 3, 4, 5).foldLeft(acc -> i -> acc + i - 1, 0)); // 10
		display(list(1, 2, 3, 4, 5).foldLeft((acc, i) -> acc + i - 1, 0)); // 10
		display(list(1, 2, 3, 4, 5).foldLeft1(acc -> i -> acc + i - 1)); // 11
		display(list(1, 2, 3, 4, 5).foldLeft1((acc, i) -> acc + i - 1)); // 11
		display(list(1, 2, 3, 4, 5).foldRight(acc -> i -> acc + i - 1, 0)); // 10
		display(list(1, 2, 3, 4, 5).foldRight((acc, i) -> acc + i - 1 , 0)); // 10
		display(list(1, 2, 3, 4, 5).forall(i -> i % 2 == 0)); // false
		list(1, 2, 3, 4, 5).foreachDoEffect(i -> System.out.print(i));System.out.println(); // 12345
		display(List.fromString("abcde")); // List(a,b,c,d,e)
		display(list(2, 2, 3, 3).group(Equal.equal(a -> b -> a == b))); // List(List(2,2),List(3,3))
		display(list(1, 2, 3, 4, 5).groupBy(i -> i % 2, intOrd)); // TreeMap((0: List(4,2)),(1: List(5,3,1)))
		display(list(1, 2, 3, 4, 5).groupBy(i -> i % 2, i -> i * 2, Ord.ord(a -> b -> Ordering.fromInt(a - b)))); // TreeMap((0: List(8,4)),(1: List(10,6,2)))
		display(list(1, 2, 3, 4, 5).head()); // 1
		display(list(1, 2, 3, 4, 5).headOption()); // Some(1)
		display(list(1, 2, 3, 4, 5).index(2)); // 3
		display(list(1, 2, 3, 4, 5).init()); // List(1,2,3,4)
		display(list(1, 2, 3, 4, 5).inits()); // List(List(),List(1),List(1,2),List(1,2,3),List(1,2,3,4),List(1,2,3,4,5))
		display(list(1, 2, 3, 4, 5).insertBy(a -> b -> Ordering.fromInt(a - b), 3)); // List(1,2,3,3,4,5)
		display(list(1, 2, 3).intercalate(list(list(9, 9), list(10, 10), list(11, 11)))); // List(9,9,1,2,3,10,10,1,2,3,11,11)
		display(list(1, 2, 3).intersperse(9)); // List(1,9,2,9,3)
		display(list(1, 2, 3).isEmpty()); // false
		display(list(1, 2, 3).isNotEmpty()); // true
		display(list(1, 2, 3).isPrefixOf(intEqual, list(1, 2, 3, 4, 5))); // true
		display(list(1).isSingle()); // true
		display(list(1, 2, 3).isSuffixOf(intEqual, list(0, 1, 2, 3))); // true
		display(List.iterableList(java.util.Arrays.asList(1, 2, 3))); // List(1,2,3)
		display(List.iterateWhile(i -> i + 1, i -> i < 10, 1)); // List(1,2,3,4,5,6,7,8,9)
		display(List.join(list(list(1, 2), list(3, 4)))); // List(1,2,3,4)
		display(list(1, 2, 3).last()); // 3
		display(list(1, 2, 3).length()); // 3
		display(List.<Integer, Integer, Integer>liftM2(a -> b -> a * b).f(list(1, 2, 3)).f(list(1, 2, 3))); // List(1,2,3,2,4,6,3,6,9)
		display(List.lookup(intEqual, list(P.p(1, 2), P.p(3, 4)), 1)); // Some(2)
		display(list(1, 2, 3).map(i -> i * 2)); // List(2,4,6)
		display(list(1, 2, 3).<Integer, Integer>mapM(a -> b -> a * b).f(3)); // List(3,6,9)
		display(list(1, 2, 3).mapMOption(i -> i % 2 == 0 ? Option.some(i / 2) : Option.none())); // None
		display(list(1, 2, 3).mapMOption(i -> i > 0 ? Option.some(i / 2) : Option.none())); // Some(List(1,2,3))
		display(list(1, 2, 3).maximum(intOrd)); // 3
		display(list(1, 2, 3).minimumOption(intOrd)); // Some(1)
		display(list(1, 2, 3).minus(intEqual, list(3, 4, 5))); // List(1,2)
		display(list(1, 2, 2, 2, 3).mode(intOrd)); // 2
		display(List.nil()); // List()
		display(list(1, 2, 2, 3, 3).nub()); // List(1,2,3)
		display(list().orHead(() -> -1)); // -1
		display(list().orTail(() -> list(1, 2))); // List(1,2)
		display(list(1, 2, 3, 4, 5).partition(i -> i % 2 == 0)); // (List(2,4),List(1,3,5))
		display(list(1, 2, 3, 4, 5).partition(3)); // List(List(1,2,3),List(4,5))
		display(List.range(1, 10)); // List(1,2,3,4,5,6,7,8,9)
		display(list(1, 2, 3, 4, 5).removeAll(i -> i % 2 == 0)); // List(1,3,5)
		display(List.replicate(3, 3)); // List(3,3,3)
		display(list(1, 2, 3, 4, 5).reverse()); // List(5,4,3,2,1)
		display(list(1, 2, 3).sequence(list('a', 'b'))); // List(a,b,a,b,a,b)
		display(List.single(3)); // List(3)
		display(list(1, 2, 3).snoc(4)); // List(1,2,3,4)
		display(list(3, 2, 1).sort(intOrd)); // List(1,2,3)
		// takeWhile + dropWhile
		display(list(1, 2, 3, 4, 5).span(i -> i < 3)); // (List(1,2),List(3,4,5))
		display(list(1, 2, 3, 4, 5).splitAt(3)); // (List(1,2,3),List(4,5))
		display(list(1, 2, 3, 4, 5).tail()); // List(2,3,4,5)
		display(list(1, 2, 3, 4, 5).tailOption()); // Some(List(2,3,4,5))
		display(list(1, 2, 3, 4, 5).tails()); // List(List(1,2,3,4,5),List(2,3,4,5),List(3,4,5),List(4,5),List(5),List())
		display(list(1, 2, 3, 4, 5).take(3)); // List(1,2,3)
		display(list(1, 2, 3, 4, 5).takeWhile(i -> i < 3)); // List(1,2)
		display(list(1, 2, 3, 4, 5).toArray()); // Array(1,2,3,4,5)
		display(list(1, 2, 3, 4, 5).toJavaList()); // [1, 2, 3, 4, 5]
		// traverse (\i -> [i, i + 1]) [1, 2, 3]
		display(list(1, 2, 3).traverseList(i -> list(i, i + 1))); // List(List(1,2,3),List(1,2,4),List(1,3,3),List(1,3,4),List(2,2,3),List(2,2,4),List(2,3,3),List(2,3,4))
		display(list(1, 2, 3).traverseOption(i -> i % 2 == 0 ? Option.some(i / 2) : Option.none())); // None
		display(list(2, 4, 6).traverseOption(i -> i % 2 == 0 ? Option.some(i / 2) : Option.none())); // Some(List(1,2,3))
		display(list(1, 2, 3).uncons((a, b) -> b.head(), 0)); // 2
		// unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
		display(List.unfold(b -> b == 0 ? Option.none() : Option.some(P.p(b, b - 1)), 10)); // List(10,9,8,7,6,5,4,3,2,1)
		display(List.unzip(list(P.p(1, 2), P.p(3, 4)))); // (List(1,3),List(2,4))
		display(list(1, 2, 3).zip(list('a', 'b', 'c'))); // List((1,a),(2,b),(3,c))
		display(list(1, 2, 3).zipIndex()); // List((1,0),(2,1),(3,2))
		display(list(1, 2, 3).zipWith(list(1, 2, 3), a -> b -> a * b)); // List(1,4,9)
		display(list(1, 2, 3).zipWith(list(1, 2, 3), (a, b) -> a * b)); // List(1,4,9)
	}

}

Array

package fp;

import fj.P;
import fj.data.Array;

import static fj.Unit.unit;
import static fj.data.Array.array;
import static fj.data.Array.iterableArray;

public class FJArray {

    static void display(Object o) { System.out.println(o); }
	public static void main(String[] args) {
		display(array(1, 2).append(array(3))); // Array(1,2,3)
		display(array(1, 2, 3).apply(array(i -> i + 3, i -> i * 2))); // Array(4,5,6,2,4,6)
		display(array(new Integer[]{1, 2, 3})); // Array(1,2,3)
		display(array(1, 2, 3).bind(i -> array(i, i * 2))); // Array(1,2,2,4,3,6)
		display(array(1, 2, 3).bind(array(4, 5, 6), x -> y -> x * y)); // Array(4,5,6,8,10,12,12,15,18)
		display(array(1, 2, 3).bind(array(4, 5, 6), (x, y) -> x * y)); // Array(4,5,6,8,10,12,12,15,18)
		display(Array.empty()); // Array()
		display(array(1, 2, 3, 4, 5).exists(i -> i % 3 == 1)); // true
		display(array(1, 2, 3, 4, 5).filter(i -> i % 2 == 1)); // Array(1,3,5)
		display(array(1, 2, 3, 4, 5).find(i -> i / 3 == 1)); // Some(3)
		display(array(1, 2, 3, 4, 5).foldLeft(acc -> i -> acc + i - 1, 0)); // 10
		display(array(1, 2, 3, 4, 5).foldLeft((acc, i) -> acc + i - 1, 0)); // 10
		display(array(1, 2, 3, 4, 5).foldRight(acc -> i -> acc + i - 1, 0)); // 10
		display(array(1, 2, 3, 4, 5).foldRight((acc, i) -> acc + i - 1, 0)); // 10
		display(array(1, 2, 3, 4, 5).forall(i -> i % 2 == 0)); // false
		array(1, 2, 3, 4, 5).foreach(i -> {System.out.print(i); return unit();});System.out.println(); // 12345
		array(1, 2, 3, 4, 5).foreachDoEffect(i -> System.out.print(i));System.out.println(); // 12345
		display(array(1, 2, 3, 4, 5).get(3)); // 4
		display(array(1, 2, 3).isEmpty()); // false
		display(array(1, 2, 3).isNotEmpty()); // true
		display(iterableArray(java.util.Arrays.asList(1, 2, 3))); // Array(1,2,3)
		display(Array.join(array(array(1, 2), array(3, 4)))); // Array(1,2,3,4)
		display(array(1, 2, 3).length()); // 3
		display(array(1, 2, 3).map(i -> i * 2)); // Array(2,4,6)
		display(Array.range(1, 10)); // Array(1,2,3,4,5,6,7,8,9)
		display(array(1, 2, 3, 4, 5).reverse()); // Array(5,4,3,2,1)
		display(array(1, 2, 3, 4, 5).scanLeft(acc -> i -> acc + i - 1, 0)); // Array(0,1,3,6,10)
		display(array(1, 2, 3, 4, 5).scanLeft((acc, i) -> acc + i - 1, 0)); // Array(0,1,3,6,10)
		display(array(1, 2, 3, 4, 5).scanLeft1(acc -> i -> acc + i - 1)); // Array(1,2,4,7,11)
		display(array(1, 2, 3, 4, 5).scanLeft1((acc, i) -> acc + i - 1)); // Array(1,2,4,7,11)
		display(array(1, 2, 3, 4, 5).scanRight(acc -> i -> acc + i - 1, 0)); // Array(10,10,9,7,4)
		display(array(1, 2, 3, 4, 5).scanRight((acc, i) -> acc + i - 1, 0)); // Array(10,10,9,7,4)
		display(array(1, 2, 3, 4, 5).scanRight1(acc -> i -> acc + i - 1)); // Array(11,11,10,8,5)
		display(array(1, 2, 3, 4, 5).scanRight1((acc, i) -> acc + i - 1)); // Array(11,11,10,8,5)
		display(array(1, 2, 3).sequence(array('a', 'b'))); // Array(a,b,a,b,a,b)
		display(Array.single(3)); // Array(3)
		display(Array.unzip(array(P.p(1, 2), P.p(3, 4)))); // (Array(1,3),Array(2,4))
		display(array(1, 2, 3).zip(array('a', 'b', 'c'))); // Array((1,a),(2,b),(3,c))
		display(array(1, 2, 3).zipIndex()); // Array((1,0),(2,1),(3,2))
		display(array(1, 2, 3).zipWith(array(1, 2, 3), a -> b -> a * b)); // Array(1,4,9)
		display(array(1, 2, 3).zipWith(array(1, 2, 3), (a, b) -> a * b)); // Array(1,4,9)
	}

}

Option

package fp;

import fj.data.List;
import fj.data.Option;
import fj.function.Effect1;

import static fj.Unit.unit;
import static fj.data.Option.some;

public class FJOption {

	static void display(Object o) { System.out.println(o); }
	public static void main(String[] args) {
		Effect1<Object> printer = o -> System.out.println(o);
		printer(some(3).apply(some(i -> i * 2))); // Some(6)
		printer(some(3).bind(i -> some(i * 2))); // Some(6)
		printer(some(3).bind(some(2), a -> b -> a * b)); // Some(6)
		printer(some(3).bindProduct(some('a'))); // Some((3,a))
		printer(some(3).exists(i -> i % 2 == 1)); // true
		printer(some(2).exists(i -> i % 2 == 1)); // false
		printer(Option.<Integer>none().exists(i -> i % 2 == 1)); // false
		printer(some(3).filter(i -> i % 2 == 1)); // Some(3)
		printer(some(2).filter(i -> i % 2 == 1)); // None
		printer(Option.<Integer>none().filter(i -> i % 2 == 1)); // None
		printer(some(3).forall(i -> i % 2 == 1)); // true
		printer(some(2).forall(i -> i % 2 == 1)); // false
		printer(Option.<Integer>none().forall(i -> i % 2 == 1)); // true
		some(3).foreach(i -> {System.out.print(i); return unit();});System.out.println(); // 3
		some(3).foreachDoEffect(i -> System.out.print(i));System.out.println(); // 3
		printer(Option.fromNull(1)); // Some(1)
		printer(Option.fromString("abc")); // Some(abc)
		printer(Option.iif(true, 3)); // Some(3)
		printer(Option.iif(false, 3)); // None
		printer(Option.iif(i -> i % 2 == 1, 3)); // Some(3)
		printer(some(3).isNone()); // false
		printer(some(3).isSome()); // true
		printer(Option.join(some(some(3)))); // Some(3)
		printer(some(3).length()); // 1
		printer(Option.<Integer>none().length()); // 0
		printer(some(3).liftM2(some(2), (x, y) -> x * y)); // Some(6)
		printer(some(3).map(i -> i * 3)); // Some(9)
		printer(some(3).orElse(some(0))); // Some(3)
		printer(Option.<Integer>none().orElse(some(0))); // Some(0)
		printer(Option.<Integer>none().orSome(3)); // 3
		printer(Option.sequence(List.list(some(1), some(2), some(3)))); // Some(List(1,2,3))
		printer(some(3).sequence(some('a'))); // Some(a)
		printer(Option.somes(List.list(some(1), some(2), some(3)))); // List(1,2,3)
		printer(some(3).traverseList(i -> List.list(1, 2, 3))); // List(Some(1),Some(2),Some(3))
		printer(some(3).traverseOption(i -> i % 2 == 1 ? some(i) : Option.none())); // Some(Some(3))
	}

}

Map

package fp;

import fj.P;
import fj.data.HashMap;
import fj.data.List;
import fj.data.TreeMap;

import static fj.Ord.charOrd;
import static fj.Ord.intOrd;
import static fj.data.HashMap.arrayHashMap;
import static fj.data.TreeMap.treeMap;

public class FJMap {

    static void display(Object o) { System.out.println(o); }
	static void display2(Object o) { System.out.print(o); }
	public static void main(String[] args) {
		{
			HashMap<Integer, Character> map = arrayHashMap(P.p(1, 'a'), P.p(2, 'b')); display(map.toMap()); // {1=a, 2=b}
			map.delete(1); display(map.toMap()); // {2=b}
			map.clear(); display(map.toMap()); // {}
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).contains(1)); // true
			arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).foreachDoEffect(FJMap::display2); display(""); // (1,a)(2,b)
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).get(1)); // Some(a)
			map = arrayHashMap(P.p(1, 'a'), P.p(2, 'b')); display2(map.getDelete(1)); display(map.toMap()); // Some(a){2=b}
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).isEmpty()); // false
			display(arrayHashMap().isEmpty()); // true
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).keys()); // List(1,2)
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).map(i -> i + 1, c -> (char)(c + 1)).toMap()); // {2=b, 3=c}
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).map(kv -> P.p(kv._1() + 1, (char)(kv._2() + 1))).toMap()); // {2=b, 3=c}
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).mapKeys(i -> i + 1).toMap()); // {2=a, 3=b}
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).mapValues(c -> (char)(c + 1)).toMap()); // {1=b, 2=c}
			map = arrayHashMap(P.p(1, 'a'), P.p(2, 'b')); map.set(3, 'c'); display(map.toMap()); // {1=a, 2=b, 3=c}
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).size()); // 2
			display(arrayHashMap().size()); // 0
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).toArray()); // Array((1,a),(2,b))
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).toList()); // List((1,a),(2,b))
			display(arrayHashMap(P.p(1, 'a'), P.p(2, 'b')).values()); // List(a,b)
		}
		{
			TreeMap<Integer, Character> map = treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')); display(map.toMutableMap()); // {1=a, 2=b}
			map.delete(1); display(map.toMutableMap()); // {1=a, 2=b}
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).contains(1)); // true
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).get(1)); // Some(a)
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).isEmpty()); // false
			display(treeMap(intOrd).isEmpty()); // true
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).keys()); // List(1,2)
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).map(c -> (char)(c + 1))); // TreeMap((1: b),(2: c))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).max()); // Some((2,b))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).minKey()); // Some(1)
			map = treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')); map.set(3, 'c'); display(map.toMutableMap()); // {1=a, 2=b}
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b'), P.p(3, 'c')).split(charOrd, 2)); // (Set(a),Some(b),Set(c))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b'), P.p(3, 'c')).splitLookup(2)); // (TreeMap((1: a)),Some(b),TreeMap((3: c)))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).size()); // 2
			display(treeMap(intOrd).size()); // 0
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).toList()); // List((1,a),(2,b))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).toListReverse()); // List((2,b),(1,a))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).union(List.list(P.p(3, 'c')))); // TreeMap((1: a),(2: b),(3: c))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).union(treeMap(intOrd, P.p(3, 'c')))); // TreeMap((1: a),(2: b),(3: c))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).update(2, c -> (char)(c + 1))); // (true,TreeMap((1: a),(2: c)))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).update(3, c -> (char)(c + 1), 'z')); // TreeMap((1: a),(2: b),(3: z))
			display(treeMap(intOrd, P.p(1, 'a'), P.p(2, 'b')).values()); // List(a,b)
		}
	}

}

Set

package fp;

import fj.Monoid;
import fj.Ord;
import fj.Ordering;
import fj.data.HashSet;
import fj.data.Set;

import static fj.Ord.intOrd;
import static fj.data.HashSet.hashSet;
import static fj.data.HashSet.iterableHashSet;
import static fj.data.Set.iterableSet;
import static fj.data.Set.set;

public class FJSet {

	static void display(Object o) { System.out.println(o); }
	static void display2(Object o) { System.out.println(o); }
	public static void main(String[] args) {
		{
			Set<Integer> set = set(intOrd, 1, 2); display(set.toJavaSet()); // [1, 2]
			display(set.bind(intOrd, a -> set(intOrd, a, a * 2))); // Set(1,2,4)
			display(set.delete(1)); // true
			display(set.size()); // 1
			display(Set.empty(intOrd).toJavaSet()); // []
            display(set(intOrd, 1, 2, 3, 4).filter(a -> a % 2 == 0)); // Set(2,4)
            display(set(intOrd, 1, 2, 3, 4).foldMap(a -> a, Monoid.intAdditionMonoid)); // 10
            display(set(intOrd, 1, 2, 3, 4).foldMapRight(a -> a, Monoid.intAdditionMonoid)); // 10
            display(set(intOrd, 1, 2).insert(3).toJavaHashSet()); // [1, 2, 3]
            display(set(intOrd, 1, 2, 3).intersect(set(intOrd, 3, 4, 5))); // Set(3)
            display(set(intOrd).isEmpty()); // true
			display(iterableSet(intOrd, java.util.Arrays.asList(1, 2, 3))); // Set(1,2,3)
            display(Set.join(intOrd, set(Ord.ord(a -> b -> Ordering.fromInt(a.size() - b.size())), set(intOrd, 1, 2, 3), set(intOrd, 3, 4, 5)))); // Set(3,4,5)
            display(set(intOrd, 1, 2, 3, 4).lookup(3)); // Some(3)
            display(set(intOrd, 1, 2, 3, 4).lookupGE(3)); // Some(3)
            display(set(intOrd, 1, 2, 3, 4).lookupGT(3)); // Some(4)
            display(set(intOrd, 1, 2, 3, 4).lookupLE(3)); // Some(3)
            display(set(intOrd, 1, 2, 3, 4).lookupLT(3)); // Some(2)
            display(set(intOrd, 1, 2, 3).map(intOrd, a -> a + 1)); // Set(2,3,4)
            display(set(intOrd, 1, 2, 3).max());
            display(set(intOrd, 1, 2, 3).member(3));
            display(set(intOrd, 1, 2, 3).minus(set(intOrd, 3, 4, 5)));
			display(set(intOrd, 1, 2).isEmpty()); // false
            display(Set.single(intOrd, 3)); // Set(3)
            display(set(intOrd, 1, 2, 3).size()); // 3
            display(set(intOrd, 1, 2, 3).split(2)); // (Set(1),Some(2),Set(3))
            display(set(intOrd, 1, 2).subsetOf(set(intOrd, 1, 2, 3))); // true
            display(set(intOrd, 1, 2).toList()); // List(1,2)
            display(set(intOrd, 1, 2).toListReverse()); // List(2,1)
            display(set(intOrd, 1, 2).toStreamReverse().toList()); // List(2,1)
            display(set(intOrd, 1, 2, 3).union(set(intOrd, 3, 4, 5))); // Set(1,2,3,4,5)
            display(set(intOrd, 1, 2, 3).update(2, a -> a + 1)); // (true,Set(1,3))
		}
		{
			HashSet<Integer> set = hashSet(1, 2); display(set.toJavaSet()); // [1, 2]
			display(set.contains(1)); // true
			display(set.delete(1)); // true
			set.clear(); display(set.toJavaSet()); // []
			display(iterableHashSet(java.util.Arrays.asList(1, 2, 3)).toJavaSet()); // [1, 2, 3]
			set.set(3); display(set.toJavaSet()); // [3]
			display(set.size()); // 1
			display(HashSet.empty().toJavaSet()); // []
			display(hashSet(1, 2).isEmpty()); // false
			display(hashSet().isEmpty()); // true
			display(hashSet(1, 2).toList()); // List(1,2)
		}
	}

}

Seq

package fp;

import fj.data.Seq;

import static fj.data.Seq.seq;

public class FJSeq {

	static void display(Object o) { System.out.println(o); }
	public static void main(String[] args) {
		display(seq(1, 2).append(seq(3))); // Seq(1,2,3)
		display(seq(1, 2).cons(3)); // Seq(3,1,2)
		display(seq(1, 2, 3, 4, 5).delete(2)); // Seq(1,2,4,5)
		display(seq(1, 2, 3, 4, 5).drop(2)); // Seq(3,4,5)
		display(Seq.empty()); // Seq()
		display(seq(1, 2, 3, 4, 5).filter(i -> i % 2 == 1)); // Seq(1,3,5)
		display(seq(1, 2, 3, 4, 5).foldLeft((acc, i) -> acc + i - 1, 0)); // 10
		display(seq(1, 2, 3, 4, 5).foldRight((acc, i) -> acc + i - 1, 0)); // 10
		display(seq(1, 2, 3, 4, 5).head()); // 1
		display(seq(1, 2, 3, 4, 5).headOption()); // Some(1)
		display(seq(1, 2, 3, 4, 5).index(2)); // 3
		display(seq(1, 2, 3, 4, 5).init()); // Seq(1,2,3,4)
		display(seq(1, 2, 3, 4, 5).insert(3, 6)); // Seq(1,2,3,6,4,5)
		display(seq(1, 2, 3).isEmpty()); // false
		display(seq(1, 2, 3).isNotEmpty()); // true
		display(seq(1, 2, 3, 4, 5).last()); // 5
		display(seq(1, 2, 3, 4, 5).length()); // 5
		display(seq(1, 2, 3).map(i -> i * 2)); // Seq(2,4,6)
		display(Seq.single(3)); // Seq(3)
		display(seq(1, 2, 3).snoc(4)); // Seq(1,2,3,4)
		display(seq(1, 2, 3).split(1)); // (Seq(1),Seq(2,3))
		display(seq(1, 2, 3, 4, 5).tail()); // Seq(2,3,4,5)
		display(seq(1, 2, 3, 4, 5).take(3)); // Seq(1,2,3)
		display(seq(1, 2, 3, 4, 5).toList()); // List(1,2,3,4,5)
		display(seq(1, 2, 3, 4, 5).toJavaList()); // [1, 2, 3, 4, 5]
		display(seq(1, 2, 3, 4, 5).update(2, 6)); // Seq(1,2,6,4,5)
	}

}

Thẻ: Functional Java lập trình hàm Java thư viện lập trình chức năng

Đăng vào ngày 19 tháng 5 lúc 19:53