logoalt Hacker News

_old_dude_today at 10:23 AM2 repliesview on HN

You need more than that for the example with setTimeout(). It requires to be able to freeze the stack and then go back later.

You need stackful coroutine (like goroutine) for that.


Replies

tometoday at 11:15 AM

That's very interesting, thanks! It gave me a brainwave and I wondered I could implement that in Bluefin. I'm pretty sure Bluefin's Request[1] is a second class stackful coroutine, and sure enough it turns out to be possible, so I'm pleased about that.

    -- ghci> example
    -- Hello
    -- World
    -- Timed out
    example = runEff $ \io -> awaitYield (receiver io) sender
    
    receiver ::
      (e1 <: es, e2 <: es) =>
      IOE e1 ->
      Await String e2 ->
      Eff es ()
    receiver io a = do
      r1 <- await a
      effIO io (putStrLn r1)
    
      r2 <- await a
      effIO io (putStrLn r2)
    
      mr3 <- timeout io 0 (await a)
      effIO io $ case mr3 of
        Nothing -> putStrLn "Timed out"
        Just r3 -> putStrLn r3
    
    sender ::
      e1 <: es =>
      Yield String e1 ->
      Eff es ()
    sender y = do
      yield y "Hello"
      yield y "World"
      yield y "More"
    
    timeout ::
      e1 <: es =>
      IOE e1 ->
      Int ->
      Eff es r ->
      Eff es (Maybe r)
    timeout io t m = withEffToIO
      (\effToIO -> System.Timeout.timeout t (effToIO (\_ -> useImpl m)))
      io
mjmastoday at 12:19 PM

Or in Lua you'd wrap the initial call in a coroutine, possibly with coronest[a] or something similar to make handling the effects at the right layer easier.

And so then the outer code is a loop around coroutine.resume, and the inner code uses coroutine.yield to perform an effect.

[a]: https://github.com/saucisson/lua-coronest