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); }