For the sake of example let's define a toy automaton type:
data Automaton =
Auto
{ success ::
Automaton
, failure ::
Automaton
}
This structure is designed to by cyclic, we can imagine each Automaton
as a state with success and failure transitions to other states. So finite automata must be defined recursively. For example here is the simplest automaton:
sink =
Auto sink sink
It consists of 1 state that always transitions to itself. If we want we can make more complex automata:
-- Transitions to a sink once it encounters a failure
otto1 =
Auto otto1 sink
-- Mutually recursive automata
otto2 =
Auto otto2 otto3
otto3 =
Auto otto3 otto2
These are nice. But it might be nice to take user input and construct an automaton. For example maybe build one out of a transition matrix. Here's a naive implementation:
fromTransition :: [(Int, Int)] -> Automaton
fromTransition tMatrix =
go 0
where
go n =
let
(succ, fail) =
tMatrix !! n
in
Auto (go succ) (go fail)
However when we try to do this there starts to be an issue. Our previous examples which were O(1)
to follow a transition. However automata produced by this are O(n)
to follow a transition, since barring caching, a list must be indexed every time we make a transition. In addition, the input list must be kept in memory as long as this automaton is. Making this basically just worse than using the transition matrix as the automaton.
What I'd really like is automata built dynamically with the method to be just as performant as ones built statically like the ones shown earlier. I'd like some way to analyze the input, construct an automaton and then free the input up up.
In a language with mutation this is easy to do because we can create the structure bit by bit, leaving holes behind to correct later.
I'd also really like to not drag the IO
in because once introduced it can't be contained.
Is there a nice way to allocate cyclic structures dynamically like I want?
Automaton
type is not very useful since there is no way to distinguish one value from another. So,fromTransition _ = let a = Auto a a in a
would technically be a correct answer. Of course, adding some field toAutomaton
, say anInt
, makes the problem no longer trivial. – Parvenu