Astrazione per strutture iterative

This commit is contained in:
Fabio Scotto di Santolo
2020-01-23 21:07:58 +01:00
committed by Fabio Scotto di Santolo
parent 46cdb250e3
commit 8badda88cf
6 changed files with 288 additions and 3 deletions

View File

@@ -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 {

View File

@@ -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;
}
}

View File

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

View File

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

View File

@@ -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;
}
}

View File

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