package scotch.data.ratio;
import static java.util.Arrays.asList;
import static scotch.runtime.RuntimeSupport.applicable;
import static scotch.runtime.RuntimeSupport.box;
import static scotch.runtime.RuntimeSupport.callable;
import static scotch.symbol.Value.Fixity.LEFT_INFIX;
import static scotch.symbol.type.TypeDescriptors.fn;
import static scotch.symbol.type.TypeDescriptors.sum;
import static scotch.symbol.type.TypeDescriptors.var;
import java.util.List;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Getter;
import scotch.runtime.Applicable;
import scotch.runtime.Callable;
import scotch.symbol.DataType;
import scotch.symbol.TypeParameter;
import scotch.symbol.TypeParameters;
import scotch.symbol.Value;
import scotch.symbol.ValueType;
import scotch.symbol.type.TypeDescriptor;
@SuppressWarnings("unused")
@DataType(memberName = "Ratio", parameters = {
@TypeParameter(name = "a")
})
public abstract class Ratio<A> {
public static TypeDescriptor TYPE = sum("scotch.data.ratio.Ratio", asList(var("a")));
@TypeParameters
public static List<TypeDescriptor> parameters() {
return asList(var("a"));
}
@Value(memberName = "Ratio")
public static <A> Applicable<A, Applicable<A, Ratio<A>>> ratio() {
return applicable(numerator -> applicable(denominator -> callable(() -> new RatioData<>(numerator, denominator))));
}
public static <A> Ratio<A> ratio(A numerator, A denominator) {
return new RatioData<>(box(numerator), box(denominator));
}
@ValueType(forMember = "Ratio")
public static TypeDescriptor ratio$type() {
return fn(var("a"), fn(var("a"), TYPE));
}
@Value(memberName = "%", fixity = LEFT_INFIX, precedence = 7)
public static <A> Applicable<A, Applicable<A, Ratio<A>>> ratioOperator() {
return ratio();
}
@ValueType(forMember = "%")
public static TypeDescriptor ratioOperator$type() {
return ratio$type();
}
private Ratio() {
// intentionally empty
}
@Override
public abstract boolean equals(Object o);
public abstract Callable<A> getDenominator();
public abstract Callable<A> getNumerator();
@Override
public abstract int hashCode();
@Override
public abstract String toString();
@AllArgsConstructor
@Getter
public static class RatioData<A> extends Ratio<A> {
private final Callable<A> numerator;
private final Callable<A> denominator;
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof RatioData) {
RatioData other = (RatioData) o;
return Objects.equals(numerator.call(), other.numerator.call())
&& Objects.equals(denominator.call(), other.denominator.call());
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hash(numerator.call(), denominator.call());
}
@Override
public String toString() {
return "Ratio { numerator = " + numerator.call() + ", denominator = " + denominator.call() + " }";
}
}
}