From 8badda88cf4f53a35e8f765ec44f06dc11f403bb Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Thu, 23 Jan 2020 21:07:58 +0100 Subject: [PATCH] Astrazione per strutture iterative --- .../demo/AbstractControlStructureDemo.java | 46 +++++- .../fp/fpjava/type/CollectionUtilities.java | 131 ++++++++++++++++++ .../org/gym/fp/fpjava/type/OrderLine.java | 35 +++++ .../java/org/gym/fp/fpjava/type/Price.java | 33 +++++ .../java/org/gym/fp/fpjava/type/Product.java | 13 ++ .../java/org/gym/fp/fpjava/type/Weight.java | 33 +++++ 6 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 functional-programming-java/src/main/java/org/gym/fp/fpjava/type/CollectionUtilities.java create mode 100644 functional-programming-java/src/main/java/org/gym/fp/fpjava/type/OrderLine.java create mode 100644 functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Price.java create mode 100644 functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Product.java create mode 100644 functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Weight.java diff --git a/functional-programming-java/src/main/java/org/gym/fp/fpjava/demo/AbstractControlStructureDemo.java b/functional-programming-java/src/main/java/org/gym/fp/fpjava/demo/AbstractControlStructureDemo.java index 8255ef0..301836f 100644 --- a/functional-programming-java/src/main/java/org/gym/fp/fpjava/demo/AbstractControlStructureDemo.java +++ b/functional-programming-java/src/main/java/org/gym/fp/fpjava/demo/AbstractControlStructureDemo.java @@ -1,9 +1,8 @@ package org.gym.fp.fpjava.demo; -import org.gym.fp.fpjava.type.Effect; -import org.gym.fp.fpjava.type.Function; -import org.gym.fp.fpjava.type.Result; +import org.gym.fp.fpjava.type.*; +import java.util.List; import java.util.regex.Pattern; import static org.gym.fp.fpjava.type.Case.match; @@ -13,6 +12,8 @@ public class AbstractControlStructureDemo { public static void run() { doEmailValidationDemo(); + doCollectionUtilitiesDemo(); + doStore(); } private static void doEmailValidationDemo() { @@ -29,6 +30,45 @@ public class AbstractControlStructureDemo { final Effect failure = validation.failure; emailChecker.apply(email).bind(success, failure); } + + private static void doCollectionUtilitiesDemo() { + List list = CollectionUtilities.list(1, 2, 3, 4, 5); + String identity = "0"; + + // Test foldLeft + Function> f_1 = x -> y -> addSI(x, y); + String result_1 = CollectionUtilities.foldLeft(list, identity, f_1); + System.out.println(result_1); + + // Test foldRight + Function> f_2 = x -> y -> addIS(x, y); + String result_2 = CollectionUtilities.foldRightRec(list, identity, f_2); + System.out.println(result_2); + + // Test reverse + System.out.println(CollectionUtilities.reverse(list)); + } + + private static String addSI(String s, Integer i) { + return "(" + s + " + " + i + ")"; + } + + private static String addIS(Integer i, String s) { + return "(" + i + " + " + s + ")"; + } + + private static void doStore() { + Product toothPaste = new Product("Tooth paste", Price.of(1.5), Weight.of(0.5)); + Product toothBrush = new Product("Tooth brush", Price.of(3.5), Weight.of(0.3)); + List order = CollectionUtilities.list( + new OrderLine(toothPaste, 2), + new OrderLine(toothBrush, 3) + ); + Price price = CollectionUtilities.foldLeft(order, Price.ZERO, Price.sum); + Weight weight = CollectionUtilities.foldLeft(order, Weight.ZERO, Weight.sum); + System.out.printf("Total price: %s\n", price); + System.out.printf("Total weight: %s\n", weight); + } } class EmailValidation { diff --git a/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/CollectionUtilities.java b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/CollectionUtilities.java new file mode 100644 index 0000000..34ec1ac --- /dev/null +++ b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/CollectionUtilities.java @@ -0,0 +1,131 @@ +package org.gym.fp.fpjava.type; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public final class CollectionUtilities { + + public static List list() { + return Collections.emptyList(); + } + + public static List list(T value) { + return Collections.singletonList(value); + } + + public static List list(List ts) { + return Collections.unmodifiableList(new ArrayList<>(ts)); + } + + @SafeVarargs + public static List list(T... elements) { + final T[] copy = Arrays.copyOf(elements, elements.length); + return Collections.unmodifiableList(Arrays.asList(copy)); + } + + public static T head(List ts) { + if (ts.size() == 0) throw new IllegalStateException("head of empty list"); + return ts.get(0); + } + + public static List tail(List ts) { + if (ts.size() == 0) throw new IllegalStateException("tail of empty list"); + final List workingList = copy(ts); + workingList.remove(0); + return Collections.unmodifiableList(workingList); + } + + public static List append(List ts, T value) { + List newList = copy(ts); + newList.add(value); + return Collections.unmodifiableList(newList); + } + + // ES. 3.5 + public static int fold(List list, Integer identity, Function> f) { + int result = identity; + for (Integer i : list) { + result = f.apply(result).apply(i); + } + return result; + } + + // ES. 3.6 + public static U foldLeft(List list, U identity, Function> f) { + U result = identity; + for (T e : list) { + result = f.apply(result).apply(e); + } + return result; + } + + // ES. 3.7 + public static U foldRight(List list, U identity, Function> f) { + U result = identity; + for (int i = list.size(); i > 0; i--) { + result = f.apply(list.get(i - 1)).apply(result); + } + return result; + } + + // ES. 3.8 + public static U foldRightRec(List list, U identity, Function> f) { + return list.isEmpty() + ? identity + : f.apply(head(list)) + .apply(foldRightRec(tail(list), identity, f)); + } + + // ES. 3.9 + public static List reverse(List ts) { + return foldLeft(ts, list(), x -> y -> prepend(y, x)); + } + + public static List prepend(T t, List list) { + return foldLeft(list, list(t), a -> b -> append(a, b)); + } + + // ES. 3.10 + public static List mapViaFoldLeft(List list, Function f) { + return foldLeft(list, list(), x -> y -> append(x, f.apply(y))); + } + + public static List mapViaFoldRight(List list, Function f) { + return foldRight(list, list(), x -> y -> prepend(f.apply(x), y)); + } + + private static List copy(List ts) { + return new ArrayList<>(ts); + } + + public static List map(List list, Function f) { + final List newList = new ArrayList<>(); + for (T value : list) { + newList.add(f.apply(value)); + } + return Collections.unmodifiableList(newList); + } + + // ES. 3.11, 3.13 + public static List range(int start, int end) { +// List result = list(); +// int tmp = start; +// while (tmp < end) { +// result = append(result, tmp); +// tmp = tmp + 1; +// } +// return result; + return unfold(start, x -> x + 1, x -> x < end); + } + + // ES. 3.12 + public static List unfold(T seed, Function f, Function predicate) { + List result = list(); + for (T tmp = seed; predicate.apply(tmp); tmp = f.apply(tmp)) { + result = append(result, tmp); + } + return result; + } +} diff --git a/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/OrderLine.java b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/OrderLine.java new file mode 100644 index 0000000..f25ffad --- /dev/null +++ b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/OrderLine.java @@ -0,0 +1,35 @@ +package org.gym.fp.fpjava.type; + +public class OrderLine { + private Product product; + private int count; + + public OrderLine(Product product, int count) { + this.product = product; + this.count = count; + } + + public Product getProduct() { + return product; + } + + public void setProduct(Product product) { + this.product = product; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public Weight getWeight() { + return this.product.weigth.mult(this.count); + } + + public Price getAmount() { + return this.product.price.mult(this.count); + } +} diff --git a/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Price.java b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Price.java new file mode 100644 index 0000000..1108ccf --- /dev/null +++ b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Price.java @@ -0,0 +1,33 @@ +package org.gym.fp.fpjava.type; + +public class Price { + public static final Price ZERO = new Price(0.0); + public static final Function> sum = + x -> y -> x.add(y.getAmount()); + + public final double value; + + public static Price of(double value) { + if (value < 0) { + throw new IllegalArgumentException("Price must be greater than 0"); + } + return new Price(value); + } + + private Price(double value) { + this.value = value; + } + + public Price add(Price that) { + return new Price(this.value + that.value); + } + + public Price mult(int count) { + return new Price(this.value * count); + } + + @Override + public String toString() { + return Double.toString(this.value); + } +} diff --git a/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Product.java b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Product.java new file mode 100644 index 0000000..c70ec97 --- /dev/null +++ b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Product.java @@ -0,0 +1,13 @@ +package org.gym.fp.fpjava.type; + +public class Product { + public final String name; + public final Price price; + public final Weight weigth; + + public Product(String name, Price price, Weight weigth) { + this.name = name; + this.price = price; + this.weigth = weigth; + } +} diff --git a/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Weight.java b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Weight.java new file mode 100644 index 0000000..b5706b3 --- /dev/null +++ b/functional-programming-java/src/main/java/org/gym/fp/fpjava/type/Weight.java @@ -0,0 +1,33 @@ +package org.gym.fp.fpjava.type; + +public class Weight { + public static final Weight ZERO = new Weight(0.0); + public static final Function> sum = + x -> y -> x.add(y.getWeight()); + + public final double value; + + public static Weight of(double value) { + if (value < 0) { + throw new IllegalArgumentException("Weight must be greater than 0"); + } + return new Weight(value); + } + + private Weight(double value) { + this.value = value; + } + + public Weight add(Weight that) { + return new Weight(this.value + that.value); + } + + public Weight mult(int count) { + return new Weight(this.value * count); + } + + @Override + public String toString() { + return Double.toString(this.value); + } +}