[Haskell-cafe] "Tying the knot" with unknown keys

Bertram Felgenhauer bertram.felgenhauer at googlemail.com
Tue Aug 21 00:02:57 EDT 2007


David Ritchie MacIver wrote:
> Essentially I have
>
> data FSM = State { transitions :: (Map Char FSM) }
>
> and
>
> transitions' :: Regexp -> Map Char Regexp
>
> I want to lift this so that the Regexps become states of the finite state 
> machine (while making sure I set up a loop in the data structure). Tying 
> the knot is the traditional way of doing such things, but we couldn't 
> figure out a way to make it work without the set of keys known in advance 
> because of the strictness of Map in its keys (an association list was 
> suggested, and that would probably work, but it seemed a bit ugly and would 
> be fairly inefficient).
>
> In the end what I did was just work out the set of reachable regexps in 
> advance and use a standard tying the knot trick, but it felt vaguely 
> unsatisfactory (and does some repeat work which I felt should be 
> unneccessary). Anyone have a more elegant suggestion?

I have a solution that I like now, even though it involves quite a bit 
of code. Its core idea is very simple. The main ingredient is

> data RegexpTrie a

which is a data type that represents an infinite trie-like structure,
indexed by regular expressions. It comes with a lookup function,

> lookupRE :: RegexpTrie a -> Regexp -> a

with the obvious semantics. It also provides a function to populate
a trie,

> populateRE :: (Regexp -> a) -> RegexpTrie a

With these functions we can build a map of *all* regular expressions
to their corresponding FSM. This is where the knot-tying takes place:

> fsm :: RegexpTrie FSM
> fsm = populateRE (\re ->
>         State { transitions = Map.map (lookupRE fsm) (transitions' re) }

Finally, 'compile' becomes a trivial lookup,

> compile :: Regexp -> FSM
> compile x = lookupRE fsm x

Detailed code can be found at http://hpaste.org/2341#a3 .

enjoy,

Bertram


More information about the Haskell-Cafe mailing list