package scotch.data.num; import static java.util.Arrays.asList; import static scotch.runtime.RuntimeSupport.applicable; import static scotch.runtime.RuntimeSupport.flatCallable; import static scotch.symbol.Value.Fixity.LEFT_INFIX; import static scotch.symbol.Value.Fixity.PREFIX; import static scotch.symbol.type.TypeDescriptors.fn; import static scotch.symbol.type.TypeDescriptors.var; import scotch.data.int_.Int; import scotch.runtime.Applicable; import scotch.runtime.Callable; import scotch.runtime.RuntimeSupport; import scotch.symbol.Member; import scotch.symbol.TypeClass; import scotch.symbol.TypeParameter; import scotch.symbol.Value; import scotch.symbol.ValueType; import scotch.symbol.type.TypeDescriptor; @SuppressWarnings("unused") @TypeClass(memberName = "Num", parameters = { @TypeParameter(name = "a"), }) public interface Num<A> { @Value(memberName = "abs") static <A> Applicable<Num<A>, Applicable<A, A>> abs() { return applicable(instance -> applicable(operand -> flatCallable(() -> instance.call().abs(operand)))); } @ValueType(forMember = "abs") static TypeDescriptor abs$type() { TypeDescriptor a = var("a", asList("scotch.data.num.Num")); return fn(a, a); } @Value(memberName = "+", fixity = LEFT_INFIX, precedence = 6) static <A> Applicable<Num<A>, Applicable<A, Applicable<A, A>>> add() { return applicable(instance -> applicable(left -> applicable(right -> flatCallable(() -> instance.call().add(left, right))))); } @ValueType(forMember = "+") static TypeDescriptor add$type() { TypeDescriptor a = var("a", asList("scotch.data.num.Num")); return fn(a, fn(a, a)); } @Value(memberName = "fromInteger") static <A> Applicable<Num<A>, Applicable<Integer, A>> fromInteger() { return applicable(instance -> applicable(integer -> flatCallable(() -> instance.call().fromInteger(integer)))); } @ValueType(forMember = "fromInteger") static TypeDescriptor fromInteger$type() { return fn(Int.TYPE, var("a", asList("scotch.data.num.Num"))); } @Value(memberName = "*", fixity = LEFT_INFIX, precedence = 7) static <A> Applicable<Num<A>, Applicable<A, Applicable<A, A>>> multiply() { return applicable(instance -> applicable(left -> applicable(right -> flatCallable(() -> instance.call().multiply(left, right))))); } @ValueType(forMember = "*") static TypeDescriptor multiplyTypeDescriptor() { TypeDescriptor a = var("a", asList("scotch.data.num.Num")); return fn(a, fn(a, a)); } @Value(memberName = "negate") static <A> Applicable<Num<A>, Applicable<A, A>> negate() { return applicable(instance -> applicable(operand -> flatCallable(() -> instance.call().negate(operand)))); } @ValueType(forMember = "negate") static TypeDescriptor negate$type() { TypeDescriptor a = var("a", asList("scotch.data.num.Num")); return fn(a, a); } @Value(memberName = "-prefix", fixity = PREFIX, precedence = 9) static <A> Applicable<Num<A>, Applicable<A, A>> prefixNegate() { return negate(); } @ValueType(forMember = "-prefix") static TypeDescriptor prefixNegate$type() { return negate$type(); } @Value(memberName = "signum") static <A> Applicable<Num<A>, Applicable<A, Integer>> signum() { return applicable(instance -> applicable(operand -> flatCallable(() -> instance.call().signum(operand)))); } @ValueType(forMember = "signum") static TypeDescriptor signum$type() { return fn(var("a", asList("scotch.data.num.Num")), Int.TYPE); } @Value(memberName = "-", fixity = LEFT_INFIX, precedence = 6) static <A> Applicable<Num<A>, Applicable<A, Applicable<A, A>>> sub() { return applicable(instance -> applicable(left -> applicable(right -> flatCallable(() -> instance.call().sub(left, right))))); } @ValueType(forMember = "-") static TypeDescriptor sub$type() { TypeDescriptor a = var("a", asList("scotch.data.num.Num")); return fn(a, fn(a, a)); } @Member("abs") Callable<A> abs(Callable<A> operand); @Member("+") Callable<A> add(Callable<A> left, Callable<A> right); @Member("fromInteger") Callable<A> fromInteger(Callable<Integer> integer); @Member("*") Callable<A> multiply(Callable<A> left, Callable<A> right); @Member("negate") default Callable<A> negate(Callable<A> operand) { return sub(fromInteger(RuntimeSupport.box(0)), operand); } @Member("signum") Callable<Integer> signum(Callable<A> operand); @Member("-") default Callable<A> sub(Callable<A> left, Callable<A> right) { return add(left, negate(right)); } }