Skip to content

Instantly share code, notes, and snippets.

@sgraf812
Created December 19, 2013 13:30
Show Gist options
  • Save sgraf812/8039107 to your computer and use it in GitHub Desktop.
Save sgraf812/8039107 to your computer and use it in GitHub Desktop.
MealyMachine using functionaljava for function interfaces and tuples.
// This won't really compile and is a rather ungeneralized example only to get you familiar with the syntax.
MealyMachine<State, Element, Option<Translation>> parser = MealyMachine.fromTransitions(
State.BEFORE,
when(State.BEFORE).then(lookOutForSourceLangHeader(source)),
when(State.IN_SECTION).then(lookOutForDirectHitsHeader),
when(State.IN_DIRECT_HITS).then(parseDirectHits(source)),
when(State.FINISHED).then(doNothing)
);
private enum State {
BEFORE,
IN_SECTION,
IN_DIRECT_HITS,
FINISHED
}
// Please forgive this crappy example and focus on syntax and usage.
package core.services;
import fj.F;
import fj.P2;
import java.util.HashMap;
import java.util.Map;
/**
* Models a finite state machine after the mealy model.
*/
public class MealyMachine<TState extends Enum<TState>, TInput, TOutput> {
private final Map<TState, F<TInput, P2<TState, TOutput>>> handlers;
private TState state;
public MealyMachine(TState initial, Map<TState, F<TInput, P2<TState, TOutput>>> handlers) {
this.state = initial;
this.handlers = handlers;
}
public TState getState() {
return state;
}
public boolean isTotal() {
for (TState s : state.getDeclaringClass().getEnumConstants()) {
if (!handlers.containsKey(s)) {
return false;
}
}
return true;
}
public TOutput step(TInput input) {
P2<TState, TOutput> output = handlers.get(state).f(input);
state = output._1();
return output._2();
}
@SafeVarargs
public static <TState extends Enum<TState>, TInput, TOutput>
MealyMachine<TState, TInput, TOutput> fromTransitions(TState initial, Transition<TState, TInput, TOutput>... transitions) {
Map<TState, F<TInput, P2<TState, TOutput>>> handlers = new HashMap<>(transitions.length);
for (Transition<TState, TInput, TOutput> t : transitions) {
handlers.put(t.getState(), t.getHandler());
}
return new MealyMachine<>(initial, handlers);
}
public static <TState extends Enum<TState>> TransitionBuilder<TState> when(TState state) {
return new TransitionBuilder<>(state);
}
public static class TransitionBuilder<TState extends Enum<TState>> {
private final TState state;
public TransitionBuilder(TState state) {
this.state = state;
}
public <TInput, TOutput> Transition<TState, TInput, TOutput> then(F<TInput, P2<TState, TOutput>> handler) {
return new Transition<>(state, handler);
}
}
public static class Transition<TState, TInput, TOutput> {
private final TState state;
private final F<TInput, P2<TState, TOutput>> handler;
public Transition(TState state, F<TInput, P2<TState, TOutput>> handler) {
this.state = state;
this.handler = handler;
}
public TState getState() {
return state;
}
public F<TInput, P2<TState, TOutput>> getHandler() {
return handler;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment