Композиция монадических функций с цепочкой в Java 8
Каким-то образом я должен быть в состоянии указать цепочку, как это, в то время как значение передается через каждую функцию.
a::create -> a::processing -> a::updating -> a:uploading
В контексте следующих статей я хочу связать методы одним методом, передавая результат другому при его изменении.
https://dzone.com/articles/higher-order-functions
https://dzone.com/articles/functional-programming-java-8
моя демонстрация будет пытаться показать, что я хочу в качестве конечного результата. Это будет один параметр / аргумент, передаваемый каждому методу (например, монады), и должно быть проще указать произвольное количество методов в цепочке.
Я делал это на других языках, поэтому пытался понять, как это сделать в Java.
Все методы получат один и тот же тип аргумента и только один.
Значение класса
public class Value {
public String progress = "";
}
Классная статья
public class Article {
public void create(Value value) {
value.progress += "creating ";
}
public void processing(Value value) {
value.progress += "processing ";
}
public void updating(Value value) {
value.progress += "updating ";
}
public void uploading(Value value) {
value.progress += "uploading ";
}
}
Основной класс
public class Main {
public static void main(String[] args) {
Value v = new Value();
Article a = new Article();
a.create(v);
a.processing(v);
a.updating(v);
a.uploading(v);
}
}
3 ответа
Учитывая, что неизменяемое состояние предпочтительнее в функциональном программировании, я настроил Value
- это дает дополнительное преимущество, делая функции прогресса чище.
public class Value {
public final String progress;
public Value() {
this("");
}
public Value(final String progress) {
this.progress = progress;
}
}
Вместо методов, Article
затем имеет функции. Эти функции могут быть связаны с помощью andThen
,
import java.util.function.Function;
public class Article {
private final Function<Value, Value> create = v -> new Value(v.progress + "creating ");
private final Function<Value, Value> processing = v -> new Value(v.progress + "processing ");
private final Function<Value, Value> updating = v -> new Value(v.progress + "updating ");
private final Function<Value, Value> uploading = v -> new Value(v.progress + "uploading ");
public static void main(String[] args) {
final Article a = new Article();
final Value v = a.create.andThen(a.processing).andThen(a.updating).andThen(a.uploading).apply(new Value());
System.out.println(v.progress);
}
}
Результат System.out.println
затем creating processing updating uploading
,
Обновить
Исходя из вашего предпочтения создавать функции в методах, вам просто нужно изменить Article
реализация иметь что-то вроде этого. Обратите внимание, что я использую вашу оригинальную (изменяемую) реализацию Value
,
public class Article {
public Function<Value, Value> create() {
return v -> {
v.progress += "creating ";
return v;
};
}
public Function<Value, Value> processing() {
return v -> {
v.progress += "processing ";
return v;
};
}
public Function<Value, Value> updating() {
return v -> {
v.progress += "updating ";
return v;
};
}
public Function<Value, Value> uploading() {
return v -> {
v.progress += "uploading ";
return v;
};
}
public static void main(String[] args) {
final Article a = new Article();
final Value v = a.create()
.andThen(a.processing())
.andThen(a.updating())
.andThen(a.uploading())
.apply(new Value());
System.out.println(v.progress);
}
}
Обновление 2
Статические ссылки на методы были запрошены, так что вот, пожалуйста. Я добавлю условие, что если бы кто-нибудь подарил мне этот код, мне бы понадобилась чертовски веская причина для выбора дизайна.
public class Article {
public static Value create(Value v) {
v.progress += "creating ";
return v;
}
public static Value processing(Value v) {
v.progress += "processing ";
return v;
}
public static Value updating(Value v) {
v.progress += "updating ";
return v;
}
public static Value uploading(Value v) {
v.progress += "uploading ";
return v;
}
public static void main(String[] args) {
Optional<Value> maybeValue = Stream.of(new Value())
.map(Article::create)
.map(Article::processing)
.map(Article::updating)
.map(Article::uploading)
.findFirst();
maybeValue.ifPresent(v -> System.out.println(v.progress));
}
}
Вот один из способов объединения потоков Java8.
public static class Article {
public Stream<Value> create(Value value) {
value.progress += "creating ";
return Stream.of(value);
}
public Stream<Value> processing(Value value) {
value.progress += "processing ";
return Stream.of(value);
}
public Stream<Value> updating(Value value) {
value.progress += "updating ";
return Stream.of(value);
}
public Stream<Value> uploading(Value value) {
value.progress += "uploading ";
return Stream.of(value);
}
public Stream<Value> error(Value value) {
return Stream.empty();
}
}
public static void main(String[] args) {
Article a = new Article();
Stream.of(new Value())
.flatMap(a::create)
.flatMap(a::processing)
.flatMap(a::updating)
.flatMap(a::uploading)
.forEach(v -> System.out.println(v.progress));
Stream.of(new Value())
.flatMap(a::create)
.flatMap(a::processing)
.flatMap(a::updating)
.flatMap(a::error)
.forEach(v -> System.out.println(v.progress));
}
Выход:
creating processing updating uploading
Делаем это без изменения методов Article для возврата Stream
public static class Article {
public Value create(Value value) {
value.progress += "creating ";
return value;
}
public Value processing(Value value) {
value.progress += "processing ";
return value;
}
public Value updating(Value value) {
value.progress += "updating ";
return value;
}
public Value uploading(Value value) {
value.progress += "uploading ";
return value;
}
}
@FunctionalInterface
public interface ThrowingFunction<T, R> {
R apply(T v) throws Exception;
}
public static Function<Value, Stream<Value>> wrap(ThrowingFunction<Value, Value> call) {
return (Value v) -> {
try {
return Stream.of(call.apply(v));
} catch (Exception e) {
return Stream.empty();
}
};
}
public static void main(String[] args) {
Article a = new Article();
Stream.of(new Value())
.flatMap(wrap(a::create))
.flatMap(wrap(a::processing))
.flatMap(wrap(a::updating))
.flatMap(wrap(a::uploading))
.forEach(v -> System.out.println(v.progress));
}
Это не ответ, и он не работает, но что-то, что я разработал на основе данных ответов, чтобы приблизиться к тому, что я хочу. пожалуйста, оставьте свои правки / ответ на основании этого.
Значение
public class Value {
public String progress = "";
}
Статья - вы можете изменить подпись методов в соответствии с потребностями.
public class Article {
public Value create(Value value) {
value.progress += "creating ";
return value;
}
public Value processing(Value value) {
value.progress += "processing ";
return value;
}
public Value updating(Value value) {
value.progress = "updating ";
return value;
}
public Value uploading(Value value) {
value.progress += "uploading ";
return value;
}
}
Главное (я должен быть в состоянии сделать что-то вроде этого)
public class Main {
public static void main(String[] args) {
Article a = new Article();
final Value v = a.create
.andThen(a.processing) // or a::processing
.andThen(a.updating) // or a::updating
.andThen(a.uploading)
.apply(new Value());
System.out.println(v.progress);
}
}