Yves Parès wrote:
For the purposes of a simple strategy game, I'd like to build an EDSL that
expresses missions. A mission could be represented as a state machine.
With basic bricks such as actions (MoveTo, ShootAt...) or tests
(EnemiesAround, LowHealth...), I could (ideally dynamically) build some
strategic behaviors for the units.
I will take the example of a patrol. Applied to a unit (or a group of
units), it dictates : go from point 1 to point 2 and then go back and
repeat. But when you detect an enemy near, leave the patrol path, destroy it
and then resume your patrol where you left it.
So if I consider my mission as a monad:
data Mission = MoveTo Point | ShootAt Unit
patrol = do
MoveTo point1
MoveTo point2
patrol
[...]
So I need a way to say: A is your action of patrolling. B is your action of
surveillance. Do both in parallel, but B is preponderant, as if it successes
(if enemies are there) it takes over A. So, it is as if I was running two
state machines in parallel.
There are several methods to specify state machines, sequential
composition of actions is just one of them. Let me elaborate.
First and foremost, you can express every state machine as an automaton.
For instance, your example above could be written as
state1 --> (MoveTo point1, state2)
state2 --> (MoveTo point2, state3)
state3 --> ((), state1)
An automaton is a set of states and transitions between them, and you
should imagine that all your state machines work like this.
Of course, while all state machines *work* like this, this does not mean
that you have to *specify* them like this. For instance, writing down
the states for a long sequence of actions like
do
moveTo point1
moveTo point2
shoot
moveTo point3
...etc.
would be very cumbersome, you'd have to invent one dummy state for each
action in the sequence. And this is where do-notation comes in: it's a
way to specify long sequences of actions and have the interpreter
automatically generate the intermediate dummy states!
As you note, however, not all state machines are sequences of actions,
far from it, actually. Sometimes, you want to write
Flee --> MoveTo point0
Attack --> shoot `during` MoveTo point1
Well, nobody forces you to use do-notation in that case, right?
In other words, I propose that you invent a small set of *state machine
combinators* that allow you to freely mix do-notation (or something less
powerful) with state transitions. Parallel composition corresponds to
pairing states.
(Chances are that you can express everything with do-notation by
introducing threads and combinators like during or fork , but I don't
know whether that's the best way to go about it. It's worth trying, but
keep in mind that the goal is to have an expressive set of combinators,
not to shoehorn everything into monads.)
Best regards,
Heinrich Apfelmus
--
http://apfelmus.nfshost.com
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe