Композиция монадических функций с цепочкой в ​​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);
    }
}
Другие вопросы по тегам