Astrazione per strutture iterative
This commit is contained in:
committed by
Fabio Scotto di Santolo
parent
46cdb250e3
commit
8badda88cf
@@ -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<String> failure = validation.failure;
|
||||
emailChecker.apply(email).bind(success, failure);
|
||||
}
|
||||
|
||||
private static void doCollectionUtilitiesDemo() {
|
||||
List<Integer> list = CollectionUtilities.list(1, 2, 3, 4, 5);
|
||||
String identity = "0";
|
||||
|
||||
// Test foldLeft
|
||||
Function<String, Function<Integer, String>> f_1 = x -> y -> addSI(x, y);
|
||||
String result_1 = CollectionUtilities.foldLeft(list, identity, f_1);
|
||||
System.out.println(result_1);
|
||||
|
||||
// Test foldRight
|
||||
Function<Integer, Function<String, String>> 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<OrderLine> 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 {
|
||||
|
||||
@@ -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 <T> List<T> list() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static <T> List<T> list(T value) {
|
||||
return Collections.singletonList(value);
|
||||
}
|
||||
|
||||
public static <T> List<T> list(List<T> ts) {
|
||||
return Collections.unmodifiableList(new ArrayList<>(ts));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> List<T> list(T... elements) {
|
||||
final T[] copy = Arrays.copyOf(elements, elements.length);
|
||||
return Collections.unmodifiableList(Arrays.asList(copy));
|
||||
}
|
||||
|
||||
public static <T> T head(List<T> ts) {
|
||||
if (ts.size() == 0) throw new IllegalStateException("head of empty list");
|
||||
return ts.get(0);
|
||||
}
|
||||
|
||||
public static <T> List<T> tail(List<T> ts) {
|
||||
if (ts.size() == 0) throw new IllegalStateException("tail of empty list");
|
||||
final List<T> workingList = copy(ts);
|
||||
workingList.remove(0);
|
||||
return Collections.unmodifiableList(workingList);
|
||||
}
|
||||
|
||||
public static <T> List<T> append(List<T> ts, T value) {
|
||||
List<T> newList = copy(ts);
|
||||
newList.add(value);
|
||||
return Collections.unmodifiableList(newList);
|
||||
}
|
||||
|
||||
// ES. 3.5
|
||||
public static int fold(List<Integer> list, Integer identity, Function<Integer, Function<Integer, Integer>> f) {
|
||||
int result = identity;
|
||||
for (Integer i : list) {
|
||||
result = f.apply(result).apply(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ES. 3.6
|
||||
public static <T, U> U foldLeft(List<T> list, U identity, Function<U, Function<T, U>> f) {
|
||||
U result = identity;
|
||||
for (T e : list) {
|
||||
result = f.apply(result).apply(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ES. 3.7
|
||||
public static <T, U> U foldRight(List<T> list, U identity, Function<T, Function<U, U>> 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 <T, U> U foldRightRec(List<T> list, U identity, Function<T, Function<U, U>> f) {
|
||||
return list.isEmpty()
|
||||
? identity
|
||||
: f.apply(head(list))
|
||||
.apply(foldRightRec(tail(list), identity, f));
|
||||
}
|
||||
|
||||
// ES. 3.9
|
||||
public static <T> List<T> reverse(List<T> ts) {
|
||||
return foldLeft(ts, list(), x -> y -> prepend(y, x));
|
||||
}
|
||||
|
||||
public static <T> List<T> prepend(T t, List<T> list) {
|
||||
return foldLeft(list, list(t), a -> b -> append(a, b));
|
||||
}
|
||||
|
||||
// ES. 3.10
|
||||
public static <T, U> List<U> mapViaFoldLeft(List<T> list, Function<T, U> f) {
|
||||
return foldLeft(list, list(), x -> y -> append(x, f.apply(y)));
|
||||
}
|
||||
|
||||
public static <T, U> List<U> mapViaFoldRight(List<T> list, Function<T, U> f) {
|
||||
return foldRight(list, list(), x -> y -> prepend(f.apply(x), y));
|
||||
}
|
||||
|
||||
private static <T> List<T> copy(List<T> ts) {
|
||||
return new ArrayList<>(ts);
|
||||
}
|
||||
|
||||
public static <T, U> List<U> map(List<T> list, Function<T, U> f) {
|
||||
final List<U> newList = new ArrayList<>();
|
||||
for (T value : list) {
|
||||
newList.add(f.apply(value));
|
||||
}
|
||||
return Collections.unmodifiableList(newList);
|
||||
}
|
||||
|
||||
// ES. 3.11, 3.13
|
||||
public static List<Integer> range(int start, int end) {
|
||||
// List<Integer> 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 <T> List<T> unfold(T seed, Function<T, T> f, Function<T, Boolean> predicate) {
|
||||
List<T> result = list();
|
||||
for (T tmp = seed; predicate.apply(tmp); tmp = f.apply(tmp)) {
|
||||
result = append(result, tmp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<Price, Function<OrderLine, Price>> 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Weight, Function<OrderLine, Weight>> 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user