% fsm(Transitions, Initial, Final)
%
% fsm(-list, -nonvar, -list)

fsm([red-0-red, red-1-green, red-2-red,		% a simple finite state machine example
	 yellow-0-red, yellow-1-green, yellow-2-red,
	 green-0-yellow, green-1-yellow, green-2-red],
	red,
	[red]).


:- object(fsm(_Transitions, _Initial, _Final),
	imports(private::assignvars)).

	:- info([
		version is 1.0,
		author is 'Paulo Moura',
		date is 2005/1/8,
		comment is 'A simple implementation of finite-state machines using assignable variables and parametric objects. Adapted from a similar example by Nobukuni Kino.',
		parnames is ['Transitions', 'Initial state', 'Final states']]).

	:- public(recognise/1).
	:- mode(recognise(+list), zero_or_more).
	:- info(recognise/1,
		[comment is 'Recognise a list of events.',
		 argnames is ['Events']]).

	recognise(Events) :-
		parameter(2, Initial),
		::assignable(Current, Initial),
		recognise(Events, Current).

	recognise([], State) :-
		::State => Current,
		final_state(Current).
	recognise([Event| Events], State) :-
		::State => Current,
		transition(Event, Current, Next),
		(write(Current-Event-Next), nl
		 ;
		 write('backtracking...'), nl, fail),
		::State <= Next,
		recognise(Events, State).

	transition(Event, Current, Next) :-
		parameter(1, Transitions),
		transition(Transitions, Event, Current, Next).

	transition([Current-Event-Next| _], Event, Current, Next).
	transition([_| Transitions], Event, Current, Next):-
		transition(Transitions, Event, Current, Next).

	final_state(State) :-
		parameter(3, Final),
		final_state(Final, State).

	final_state([State| _], State).
	final_state([_| States], State) :-
		final_state(States, State).

:- end_object.