4 ms·
Somewhat related to the coroutine vs. FSM issue: http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines/ http://eli.thegreenpla
by eliben 16y ago
Somewhat related to the coroutine vs. FSM issue: http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines/ http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-al...
[apologize for the plug, but IMHO it's very relevant]
- silentbicycle 16y agoYou don't need coroutines to do this - you can use tail calls, if the language provides tail-call optimization. (Python doesn't, but Lua does.) I might post a code sample translating your FSM example later, but I need to go run errands.
- johkra 16y agoI would be interested in a code sample. I didn't know Lua supported TCO. (I bought PiL, btw, and it helped me tremendously in understanding many programming language implementation issues. Highly recommended.)
- silentbicycle 16y agoThis could be done in a couple different ways. My point was that you can use multiple functions with tail calls rather than one big self.state == self.STATE_TAG switch statement. In this case, the input for loop works like a trampoline, so the stack doesn't build up. It could have been done the same way in Python (where self.state IS the "handle next byte" method). That wouldn't be true for all FSMs, though. In something that take input one piece at a time, it'd probably still be simplest to use a coroutine. Also, everything here could be made private except new, if it mattered. I tried to make a straightforword translation of the first Python sample. It looks rather like a recursive descent parser. local header, footer, dle = '\97', '\98', '\253' function wait_header(s, byte) if byte == header then s.frame = {}; return in_msg end return wait_header end function in_msg(s, byte) if byte == dle then return after_dle elseif byte == footer then return table.concat(s.frame) else s.frame[#s.frame+1] = byte --append to frame buffer return in_msg end end function after_dle(s, byte) s.frame[#s.frame+1] = s.adf(byte) return in_msg end function new(after_dle_func) local state, func = { adf = after_dle_func, frame = {} }, wait_header return function(byte) func = func(state, byte) if type(func) == "string" then return func end end end -- test -- foo = new(function(x) print "(in after_dle_func)"; return x:upper() end) -- this is like "for /./ in string do ..." for b in string.gmatch("foo\97frame contents\253dle\98end", ".") do local res = foo(b) if res then print("GOT FRAME: ", res); break end end > dofile("/tmp/lua-6043PeX") (in after_dle_func) GOT FRAME: frame contentsDle Also, Shriram Krishnamurthi's "The Swine Before Perl" (http://www.cs.brown.edu/~sk/Publications/Talks/SwineBeforePerl/ http://www.cs.brown.edu/~sk/Publications/Talks/SwineBeforePe...) also has a good example of using tail calls to write FSMs in Scheme.
- zedshaw 16y agoThat'd be super slick. BTW, you're the guy that wrote sidereal right? I'm using it for the redis action. Very nice.
- silentbicycle 16y agoYes, and thanks. :) Have you seen my library (http://github.com/silentbicycle/tamale http://github.com/silentbicycle/tamale) for doing Erlang-style pattern matching in Lua, BTW? I still need to document it (I'm working on briefly explaining why pattern matching matters to people who have never used it), but in the mean time, a glance at the README and the test suite should suffice.
- silentbicycle 16y agoFor the translated AST, see: http://news.ycombinator.com/item?id=1801569 http://news.ycombinator.com/item?id=1801569
- corysama 16y agoI don't have a blog to plug. So, I'll shameless plug my Reddit post regarding coroutines vs. FSMs instead: http://www.reddit.com/r/programming/comments/9fcna/coroutines_as_an_alternative_to_state_machines/c0ck9ml http://www.reddit.com/r/programming/comments/9fcna/coroutine...