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)
}
}