package scotch.control.monad;
import static java.util.Arrays.asList;
import static scotch.symbol.Value.Fixity.LEFT_INFIX;
import static scotch.symbol.type.TypeDescriptors.ctor;
import static scotch.symbol.type.TypeDescriptors.fn;
import static scotch.symbol.type.TypeDescriptors.sum;
import static scotch.symbol.type.TypeDescriptors.var;
import static scotch.runtime.RuntimeSupport.applicable;
import static scotch.runtime.RuntimeSupport.callable;
import static scotch.runtime.RuntimeSupport.flatCallable;
import scotch.symbol.TypeClass;
import scotch.symbol.TypeParameter;
import scotch.symbol.Value;
import scotch.symbol.ValueType;
import scotch.symbol.type.TypeDescriptor;
import scotch.runtime.Applicable;
import scotch.runtime.Callable;
@SuppressWarnings("unused")
@TypeClass(memberName = "Monad", parameters = {
@TypeParameter(name = "m"),
})
public interface Monad {
TypeDescriptor m = var("m", asList("scotch.control.monad.Monad"));
@Value(memberName = ">>=", fixity = LEFT_INFIX, precedence = 1)
static Applicable bind() {
return applicable(
instance -> applicable(
arg -> applicable(
fn -> callable(
() -> ((Monad) instance.call()).bind(arg, (Applicable) fn)))));
}
@ValueType(forMember = ">>=")
static TypeDescriptor bind$type() {
return fn(ctor(m, var("a")), fn(fn(var("a"), ctor(m, var("b"))), ctor(m, var("b"))));
}
@Value(memberName = "fail")
static Applicable fail() {
return applicable(
instance -> applicable(
message -> callable(
() -> ((Monad) instance.call()).fail(message))));
}
@ValueType(forMember = "fail")
static TypeDescriptor fail$type() {
return fn(sum("scotch.data.string.String"), ctor(m, var("a")));
}
@Value(memberName = ">>", fixity = LEFT_INFIX, precedence = 1)
static Applicable then() {
return applicable(
instance -> applicable(
firstValue -> applicable(
nextValue -> callable(
() -> ((Monad) instance.call()).then(firstValue, nextValue)))));
}
@ValueType(forMember = ">>")
static TypeDescriptor then$type() {
return fn(ctor(m, var("a")), fn(ctor(m, var("b")), ctor(m, var("b"))));
}
@Value(memberName = "return")
static Applicable wrap() {
return applicable(
instance -> applicable(
value -> callable(
() -> ((Monad) instance.call()).wrap(value))));
}
@ValueType(forMember = "return")
static TypeDescriptor wrap$type() {
return fn(var("a"), ctor(m, var("a")));
}
Callable bind(Callable value, Applicable transformer);
Callable fail(Callable message);
default Callable then(Callable firstValue, Callable nextValue) {
return bind(firstValue, applicable(arg -> flatCallable(() -> nextValue)));
}
Callable wrap(Callable value);
}