Documentation Index
Fetch the complete documentation index at: https://docs.dairy.foundation/llms.txt
Use this file to discover all available pages before exploring further.
Lambda and StatefulLambda are the primary way to write commands in
Mercurial.
These classes are immutable command builders, that allow you to compose a
command programmatically, and are easy to read and use.
StatefulLambda is the same as Lambda, but has additional state stored in it,
that gets passed to each of its methods to manipulate.
Both Lambda and StatefulLambda start with sensible defaults:
- no requirements
- an empty init method
- an empty execute method
- instantly finishes
- an empty end method
- is interruptible
- allowed to be scheduled in OpModeState.ACTIVE only (start and loop)
Then, you can apply the builder methods to compose a new command, by adding to
or replacing components of the current command.
Construction
Both Lambda and StatefulLambda are easy to construct:
Lambda lambda = new Lamdba("command-name");
StatefulLambda<RefCell<String>> statefulLambda = new StatefulLambda<>("command-name", new RefCell<>("state"));
Our StatefulLambda will have a RefCell with a String in it as its state.
Go read the RefCell documentation in Util for how it works. We need a cell or
similar in order to obtain interior mutability for a simpler piece of data like
a String, but you could use a more complex class you’ve written yourself.
Building
There are easy methods to set parts of a Command:
lambda
.setInit(() -> {
// do w/e
})
.setExecute(() -> {
// do w/e
})
.setEnd(interrupted -> {
// do w/e
})
.setFinish(() -> {
// compute and return if the command is finished
return true;
})
// both variants are available
.setInterruptible(true)
.setInterruptible(() -> true)
// we'll used Mercurial as an example requirement
// but it would be strange to use
// you could also pass a Set of objects instead of varargs
.setRequirements(Mercurial.INSTANCE /*, varargs requirements*/)
// you could also pass a Set of OpModeStates instead of varargs
.setRunStates(OpModeState.INIT, OpModeState.ACTIVE);
statefulLambda
// stateful lambda adds equivalent methods that also get state as a parameter
.setExecute(stateRef -> {
stateRef.accept("new state");
})
.setEnd((interrupted, stateRef) -> {
if (interrupted) stateRef.accept("interrupted");
else stateRef.accept("not interrupted");
});
Or add to the pre-existing ones, we’ll demonstrate some of the add methods, but
there are equivalents for all the set methods.
lambda
.addInit(() -> {
// this will run the init already set
// then this code
})
.addFinish(finished -> {
// addFinished gives you the computed finished state of the command thus far
// and allows you to then determine if it should still finish
return finished;
})
.addInterruptible(interruptible -> {
// addInterruptible does the same
return interruptible;
});
statefulLambda
// statefulLambda has all the same methods, plus you can get the state
.addInterruptible((interruptible, state) -> {
return interruptible && state.get().equals("interruptible");
});
Remember, each of these methods are non-mutating. This means than when you call
them, you get back a new, different command. In the case of statefulLambda, they
still share the same state reference, but other than that they are totally
different.
This is a common theme across Dairy, and its not hard to deal with, but you must
keep it in mind.
Finally, any command can be converted into a Lambda or StatefulLambda
command.
Lambda converted = Lambda.from(new Sequential())
.addEnd(interrupted -> {
System.out.println("sequence ending, interrupted: " + interrupted + "!");
});
StatefulLambda<RefCell<Integer>> statefulConverted = StatefulLambda.from(new Sequential(), new RefCell<>(0))
.addEnd((interrupted, stateRef) -> {
// increment state
stateRef.accept(stateRef.get() + 1);
System.out.println("sequence ending for the " + stateRef.get() + " time, interrupted: " + interrupted + "!");
});
This process is safe for Lambda.from(Command), it does not create a new object
if the argument is already a Lambda or a StatefulLambda.
But StatefulLamba.from(Command, STATE) does not have this safety.
Lambda and StatefulLambda are clearly nice and easy ways to compose
commands! They are the recommended tool for writing commands in Mercurial.