【问题标题】:Monadic Function composition with chaining in Java 8Java 8 中带有链接的一元函数组合
【发布时间】:2017-03-14 08:05:16
【问题描述】:

当值通过每个函数传递时,我应该能够以某种方式指定这样的链。

a::create -> a::processing -> a::updating -> a:uploading

在以下文章的上下文中,我想用一种方法将方法链接起来,在修改它时将结果传递给下一种方法。

https://dzone.com/articles/higher-order-functions

https://dzone.com/articles/functional-programming-java-8

我的演示将尝试展示我想要的最终结果。这将是单个参数/参数通过管道传递给每个方法(如 monad),并且应该更容易在链中指定任意数量的方法。

我一直在用其他语言做这件事,所以试图弄清楚如何用 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);
    }
}

Suggested Link

【问题讨论】:

  • @JDC 请删除标签,答案只是理论上的,对我没有帮助,我需要一个工作示例
  • 你可能应该把它带到软件工程中(如果你希望人们与你谈论它,也许可以少一点傲慢/脾气暴躁)。
  • 不,不是那个意思,会在那里发帖
  • 顺便说一下,小错字 value.progress = "updating ";应该是 value.progress +="updating";
  • 我对你的问题有点困惑:你的代码中没有 monad,那么你真正想要编写的是什么?

标签: java monads method-chaining function-composition


【解决方案1】:

鉴于不可变状态在函数式编程中更可取,我已经调整了 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));
    }
}

【讨论】:

  • 很好。我正在编辑一些东西,我应用了你的 Value 命题,但是编译器因为最终字符串而抱怨,当你说不可变时,我的想法是对象通过链被更新的值装饰
  • 能否让文章类返回ValueFunction&lt;Value,,使其工作,因为我的函数不是单行,它们有几行代码,内联可能很麻烦。跨度>
  • 请看我的回答
  • bravo,这就是我想要的,但我从你那里学到了不可变性,你可以更新为不可变的,这样它可以帮助其他人。数以百万计的感谢。
  • 还有一个问题,如果我将Article方法标记为静态,那么a.processing()就会变成a::processing(),对了这样我就不用为Article创建一个对象了吗?
【解决方案2】:

这是与 Java8 Streams 链接的一种方式。

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

}

【讨论】:

  • 您能否编辑并添加关于如何在不返回 Stream 的情况下使用它的另一部分,例如 Steve 示例,使用 andThen,然后保持一切原样。我的方法有很多实体,我不能内联定义它们,所以你的文章定义很好
  • 请看我的回答
【解决方案3】:

这不是答案,它不起作用,但我根据给定的答案起草了一些接近我想要的东西。请根据此发布您的编辑/答案。

价值

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

【讨论】:

    猜你喜欢
    • 2018-10-27
    • 2018-08-21
    • 2018-10-27
    • 1970-01-01
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多