org.opencastproject.util.data.Either Maven / Gradle / Ivy
/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License
* at:
*
* http://opensource.org/licenses/ecl2.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.opencastproject.util.data;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.opencastproject.util.data.Option.some;
import java.util.Iterator;
import java.util.List;
/**
* An algebraic data type representing a disjoint union. By convention left is considered to represent an error while
* right represents a value.
*
* This implementation of Either
is much simpler than implementations you may know from other languages or
* libraries.
*/
public abstract class Either {
private Either() {
}
public abstract LeftProjection left();
public abstract RightProjection right();
public abstract X fold(Match visitor);
public abstract X fold(Function super A, ? extends X> left, Function super B, ? extends X> right);
public abstract boolean isLeft();
public abstract boolean isRight();
public interface Match {
X left(A a);
X right(B b);
}
/**
* Left projection of either.
*/
public abstract class LeftProjection implements Iterable {
private LeftProjection() {
}
public abstract Either either();
public abstract Either map(Function f);
public abstract Either bind(Function> f);
public Either flatMap(Function> f) {
return bind(f);
}
public abstract A value();
public abstract A getOrElse(A right);
public abstract Option toOption();
public abstract List toList();
}
/**
* Right projection of either.
*/
public abstract class RightProjection implements Iterable {
private RightProjection() {
}
public abstract Either either();
public abstract Either map(Function f);
public abstract Either bind(Function> f);
public Either flatMap(Function> f) {
return bind(f);
}
public abstract B value();
public abstract B getOrElse(B left);
public abstract Option toOption();
public abstract List toList();
}
/**
* Create a left.
*/
public static Either left(final A left) {
return new Either() {
@Override
public C fold(Match visitor) {
return visitor.left(left);
}
@Override
public LeftProjection left() {
final Either self = this;
return new LeftProjection() {
@Override
public A value() {
return left;
}
@Override
public Option toOption() {
return some(left);
}
@Override
public List toList() {
return singletonList(left);
}
@Override
public Iterator iterator() {
return toList().iterator();
}
@Override
public A getOrElse(A right) {
return left;
}
@Override
public Either either() {
return self;
}
@Override
public Either map(Function f) {
return left(f.apply(left));
}
@Override
public Either bind(Function> f) {
return f.apply(left);
}
};
}
@Override
public RightProjection right() {
final Either self = this;
return new RightProjection() {
@Override
public Either either() {
return self;
}
@Override
public Either map(Function f) {
return left(left);
}
@Override
public Either bind(Function> f) {
return left(left);
}
@Override
public B value() {
throw new Error("right projection on left does not have a value");
}
@Override
public B getOrElse(B left) {
return left;
}
@Override
public Option toOption() {
return Option.none();
}
@Override
public List toList() {
return emptyList();
}
@Override
public Iterator iterator() {
return toList().iterator();
}
};
}
@Override
public C fold(Function super A, ? extends C> leftf, Function super B, ? extends C> rightf) {
return leftf.apply(left);
}
@Override
public boolean isLeft() {
return true;
}
@Override
public boolean isRight() {
return false;
}
};
}
/**
* Create a right.
*/
public static Either right(final B right) {
return new Either() {
@Override
public C fold(Match visitor) {
return visitor.right(right);
}
@Override
public LeftProjection left() {
final Either self = this;
return new LeftProjection() {
@Override
public A value() {
throw new Error("left projection on right does not have a value");
}
@Override
public Option toOption() {
return Option.none();
}
@Override
public List toList() {
return emptyList();
}
@Override
public Iterator iterator() {
return toList().iterator();
}
@Override
public A getOrElse(A right) {
return right;
}
@Override
public Either either() {
return self;
}
@Override
public Either map(Function f) {
return right(right);
}
@Override
public Either bind(Function> f) {
return right(right);
}
};
}
@Override
public RightProjection right() {
final Either self = this;
return new RightProjection() {
@Override
public Either either() {
return self;
}
@Override
public Either map(Function f) {
return right(f.apply(right));
}
@Override
public Either bind(Function> f) {
return f.apply(right);
}
@Override
public B value() {
return right;
}
@Override
public B getOrElse(B left) {
return right;
}
@Override
public Option toOption() {
return some(right);
}
@Override
public List toList() {
return singletonList(right);
}
@Override
public Iterator iterator() {
return toList().iterator();
}
};
}
@Override
public X fold(Function super A, ? extends X> leftf, Function super B, ? extends X> rightf) {
return rightf.apply(right);
}
@Override
public boolean isLeft() {
return false;
}
@Override
public boolean isRight() {
return true;
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy