Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否有可能在Java中构造一个允许flatMap返回不同的左值的或?_Java_Functional Programming_Monads - Fatal编程技术网

是否有可能在Java中构造一个允许flatMap返回不同的左值的或?

是否有可能在Java中构造一个允许flatMap返回不同的左值的或?,java,functional-programming,monads,Java,Functional Programming,Monads,我试图理解这两种方法是如何实现的。我在将多个函数链接在一起时遇到了困难,这种链接允许在flatMap期间返回不同的Left值。我无法计算出在类型系统中它是如何可能的 最小示例代码: public class Either<A,B> { public final A left; public final B right; private Either(A a, B b) { left = a; right = b; }

我试图理解这两种方法是如何实现的。我在将多个函数链接在一起时遇到了困难,这种链接允许在
flatMap
期间返回不同的
Left
值。我无法计算出在类型系统中它是如何可能的

最小示例代码:

public class Either<A,B> {
    public final A left;
    public final B right;

    private Either(A a, B b) {
        left = a;
        right = b;
    }

    public static <A, B> Either<A, B> left(A a) {
        return new Either<>(a, null);
    }


    public static <A, B> Either<A, B> right(B b) {
        return new Either<>(null, b);
    }


    public <C> Either<A, C> flatMap(Function<B, Either<A,C>> f) {
        if (this.isRight()) return f.apply(this.right);
        else return Either.left(this.left);
    }

    // map and other useful functions....
但是,编译器将此标记为不可能

在研究了一些代码之后,我意识到这是由于我的
通用参数造成的

flatMap有两种不同的情况:

  • 我们绘制右侧地图的情况
  • 我们通过左值的情况
  • 因此,如果我的目标是启用有时从flatMap返回不同的左值,那么我的两个通用变量
    不起作用,因为如果执行案例1并且我的函数更改
    A
    ,那么案例2无效,因为
    A
    !=<代码>A'。将函数应用到右侧的行为可能已将左侧更改为不同的类型

    所有这些让我想到了这些问题:

  • 我对这两种类型行为的期望是否不正确
  • 在flatMap操作期间,是否可以返回不同的
    Left
    类型
  • 如果是这样的话,你是如何计算出这些类型的
    由于参数性,没有您想要的合理的
    flatMap()
    函数。考虑:

    Either<Foo, String> e1 = Either.left(new Foo());
    Either<Bar, String> e2 = foo.flatMap(x -> doThing2());
    Bar bar = e2.left; // Where did this come from???
    

    可以,但是旧的
    Left
    必须是新的
    Left
    的子类型或与之相等,因此可以将其强制转换。我不太熟悉Java的语法,但Scala实现看起来像:

    def flatMap[A1>:A,B1](f:B=>任一[A1,B1]):任一[A1,B1]=此匹配{
    案例右侧(b)=>f(b)
    case=>this.asInstanceOf[A1,B1]]
    }
    

    这里的
    A1>:A
    A
    指定为
    A1
    的子类型。我知道Java有一个
    语法,但我不确定它是否可以用来描述
    A1
    上的约束,就像我们在本例中需要的那样。

    关于
    或者
    的用法(
    点(…)
    ),您的平面映射似乎不够。我假设您希望平面映射像
    可选的那样工作

    Optional.flatMap
    的映射器获取一个
    T
    类型的值,并返回一个
    Optional
    ,其中
    U
    是此方法的通用类型参数。但是
    Optional
    有一个泛型类型参数
    T
    ,而
    有两个:
    A
    B
    。因此,如果您想要平面映射
    ,则仅使用一个映射是不够的

    一个映射它应该映射什么?“不是空值的值”你会说-不是吗?好的,但您首先在运行时知道这一点。您的
    flatMap
    方法是在编译时定义的。因此,您必须为每种情况提供映射

    您可以选择平面图(函数f)
    。此映射使用类型为
    B
    的值作为输入。这意味着如果映射的
    !eather.isRight()
    以下所有映射都将返回一个
    eather.left(a)
    ,其中
    a
    是第一个
    eather.left(a)
    的值。因此实际上只有
    other
    其中
    other.isRight()
    可以映射到另一个值。而且从一开始就必须是
    或.isRight()
    。这也意味着,一旦创建了
    other
    ,所有平面映射都将产生一种
    other
    。因此当前的
    flatMap
    限制
    以保持其左泛型类型。这就是你应该做的吗

    如果要无限制地平面映射
    任一
    ,则这两种情况都需要映射:
    任一.isRight()
    !.isRight()之一
    。这将允许您在两个方向上继续展开贴图

    我是这样做的:

    public class Either<A, B> {
        public final A left;
        public final B right;
    
        private Either(A a, B b) {
            left = a;
            right = b;
        }
    
        public boolean isRight() {
            return right != null;
        }
    
        @Override
        public String toString() {
            return isRight() ?
                    right.toString() :
                    left.toString();
        }
    
        public static <A, B> Either<A, B> left(A a) {
            return new Either<>(a, null);
        }
    
        public static <A, B> Either<A, B> right(B b) {
            return new Either<>(null, b);
        }
    
        public <C, D> Either<C, D> flatMap(Function<A, Either<C, D>> toLeft, Function<B, Either<C, D>> toRight) {
            if (this.isRight()) {
                return toRight.apply(this.right);
            } else {
                return toLeft.apply(this.left);
            }
        }
    
        public static void main(String[] args) {
            Either<String, String> left = Either.left(new Foo("left"))
                    .flatMap(l -> Either.right(new Bar(l.toString() + ".right")), r -> Either.left(new Baz(r.toString() + ".left")))
                    .flatMap(l -> Either.left(l.toString() + ".left"), r -> Either.right(r.toString() + ".right"));
            System.out.println(left); // left.right.right
    
            Either<String, String> right = Either.right(new Foo("right"))
                    .flatMap(l -> Either.right(new Bar(l.toString() + ".right")), r -> Either.left(new Baz(r.toString() + ".left")))
                    .flatMap(l -> Either.left(l.toString() + ".left"), r -> Either.right(r.toString() + ".right"))
                    .flatMap(l -> Either.right(l.toString() + ".right"), r -> Either.left(r.toString() + ".left"));
            System.out.println(right); // right.left.left.right
        }
    
        private static class Foo {
            private String s;
    
            public Foo(String s) {
                this.s = s;
            }
    
            @Override
            public String toString() {
                return s;
            }
        }
    
        private static class Bar {
            private String s;
    
            public Bar(String s) {
                this.s = s;
            }
    
            @Override
            public String toString() {
                return s;
            }
        }
    
        private static class Baz {
            private String s;
    
            public Baz(String s) {
                this.s = s;
            }
    
            @Override
            public String toString() {
                return s;
            }
        }
    }
    
    公共类{
    公开决赛A左;
    公共最终B权;
    二等兵(甲、乙){
    左=a;
    右=b;
    }
    公共布尔值isRight(){
    返回右侧!=null;
    }
    @凌驾
    公共字符串toString(){
    返回isRight()?
    对。toString()
    左。toString();
    }
    公共静态或左(A){
    返回新的(a,null);
    }
    公共静态任意一项权利(B){
    返回新的(null,b);
    }
    公共平面地图(左功能,右功能){
    if(this.isRight()){
    返回右侧。应用(此右侧);
    }否则{
    返回到左。应用(此。左);
    }
    }
    公共静态void main(字符串[]args){
    要么左=要么左(新的Foo(“左”))
    .flatMap(l->eather.right(新条(l.toString()+“.right”)),r->eather.left(新Baz(r.toString()+“.left”))
    .flatMap(l->eather.left(l.toString()+“.left”)、r->eather.right(r.toString()+”.right”);
    System.out.println(左);//左.右.右
    任意右=任意。右(新的Foo(“右”))
    .flatMap(l->eather.right(新条(l.toString()+“.right”)),r->eather.left(新Baz(r.toString()+“.left”))
    .flatMap(l->eather.left(l.toString()+“.left”)、r->eather.right(r.toString()+“.right”))
    .flatMap(l->eather.right(l.toString()+“.right”)、r->eather.left(r.toString()+“.left”);
    System.out.println(右);//right.left.left.right
    }
    私有静态类Foo{
    私有字符串;
    公共Foo(字符串s){
    这个.s=s;
    }
    @凌驾
    公共字符串toString(){
    返回s;
    }
    }
    专用静态类栏{
    私有字符串;
    公共酒吧{
    
    Either<Foo, String> e1 = Either.left(new Foo());
    Either<Bar, String> e2 = foo.flatMap(x -> doThing2());
    Bar bar = e2.left; // Where did this come from???
    
    public <C, D> Either<C, D> flatMap(Function<B, Either<C, D>> f) {
        if (this.isRight()) {
            return f.apply(this.right);
        } else {
            // Error: can't convert A to C
            return Either.left(this.left);
        }
    }
    
    public class Either<A, B> {
        public final A left;
        public final B right;
    
        private Either(A a, B b) {
            left = a;
            right = b;
        }
    
        public boolean isRight() {
            return right != null;
        }
    
        @Override
        public String toString() {
            return isRight() ?
                    right.toString() :
                    left.toString();
        }
    
        public static <A, B> Either<A, B> left(A a) {
            return new Either<>(a, null);
        }
    
        public static <A, B> Either<A, B> right(B b) {
            return new Either<>(null, b);
        }
    
        public <C, D> Either<C, D> flatMap(Function<A, Either<C, D>> toLeft, Function<B, Either<C, D>> toRight) {
            if (this.isRight()) {
                return toRight.apply(this.right);
            } else {
                return toLeft.apply(this.left);
            }
        }
    
        public static void main(String[] args) {
            Either<String, String> left = Either.left(new Foo("left"))
                    .flatMap(l -> Either.right(new Bar(l.toString() + ".right")), r -> Either.left(new Baz(r.toString() + ".left")))
                    .flatMap(l -> Either.left(l.toString() + ".left"), r -> Either.right(r.toString() + ".right"));
            System.out.println(left); // left.right.right
    
            Either<String, String> right = Either.right(new Foo("right"))
                    .flatMap(l -> Either.right(new Bar(l.toString() + ".right")), r -> Either.left(new Baz(r.toString() + ".left")))
                    .flatMap(l -> Either.left(l.toString() + ".left"), r -> Either.right(r.toString() + ".right"))
                    .flatMap(l -> Either.right(l.toString() + ".right"), r -> Either.left(r.toString() + ".left"));
            System.out.println(right); // right.left.left.right
        }
    
        private static class Foo {
            private String s;
    
            public Foo(String s) {
                this.s = s;
            }
    
            @Override
            public String toString() {
                return s;
            }
        }
    
        private static class Bar {
            private String s;
    
            public Bar(String s) {
                this.s = s;
            }
    
            @Override
            public String toString() {
                return s;
            }
        }
    
        private static class Baz {
            private String s;
    
            public Baz(String s) {
                this.s = s;
            }
    
            @Override
            public String toString() {
                return s;
            }
        }
    }