koka-lang / koka

Koka language compiler and interpreter
http://koka-lang.org
Other
3.16k stars 151 forks source link

async effect #378

Open pca006132 opened 7 months ago

pca006132 commented 7 months ago

Hi, I was trying to use async effect but found that the std/async module seems to be removed, which causes some of the tests to fail:

$ stack run test/async/async1.kk                           
compile: test/async/async1.kk
loading: std/core
loading: std/core/types
loading: std/core/hnd
test/async/async1.kk(4, 1): error: could not find module: std/async
 search path: /home/pca006132/code/koka/lib

I was also trying to implement async using resume, but it seems that I cannot use resume anywhere outside the handler. For example, the following code cannot compile:

effect yield
  ctl yield(): ()

fun unfair-scheduler<e>(tasks: list<() -> e()>)
  var backstore := Nil
  with handler
    ctl yield() backstore := Cons(resume, backstore)
  foreach(tasks: list<_>, fn(x) x())

  var worklist := backstore
  backstore := Nil
  while { ! worklist.is-empty }
    match worklist
      Cons(x, xs) ->
        x()
        if xs.is-empty then
          worklist := backstore
          backstore := Nil
        else
          worklist := xs

Error:

yield.kk(15, 9): error: function has not enough arguments
  context      :         x()
  term         :         x
  inferred type: (()) -> <local<_h>|_e> ()

I suspect that resume was called directly, so I tried changing the line to

    ctl yield() backstore := Cons(fn() resume(), backstore

This failed with

yield.kk(7,40): error: function has not enough arguments
  context      :                                        resume()
  term         :                                        resume
  inferred type: (_b) -> _e _a
  hint         : cannot use "resume" inside a val/fun/except clause

Using raw control:

  // ...
    raw ctl yield() backstore := Cons(rcontext, backstore)
  foreach(tasks: list<_>, fn(x) x())

  var worklist := backstore
  backstore := Nil
  while { ! worklist.is-empty }
    match worklist
      Cons(x, xs) ->
        x.resume()
  // ...

This also failed with:

yield.kk(15,11): error: function has not enough arguments
  context      :         x.resume()
  term         :           resume
  inferred type: (r : std/core/hnd/resume-context<_a,_e,_e1,_b>, x : _a) -> _e _b
  hint         : cannot use "resume" inside a val/fun/except clause

Looking at the git blame of the code responsible for the error message, it seems that this is due to a skolem escape check, not sure if it is needed due to effect handler implementation. Is this kind of operation supported?

TimWhiting commented 7 months ago

Hi, see #384 for the reintroduction of async support into Koka.

As feedback on your approach rcontext should not escape the handler clause (resume will always be resolved locally to a handler clause). Instead store a lambda that calls rcontext.resume i.e. (fn(x) rcontext.resume(x)).