koka-lang / koka

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

vector-init does not work correctly for control effects #416

Closed anfelor closed 5 months ago

anfelor commented 6 months ago

In #388, the vector-init function was changed to allow an arbitrary effect on the initialization function. While this is a welcome change for most effects, it does not play well with control effects. Consider the following program:

effect choice
  ctl flip() : bool

fun test-vector()
   with handler
     ctl flip()
       val v1 = resume(True)
       val v2 = resume(False)
       return v1.append(v2)
   with return(v) [v]
   vector-init(5, fn(i) -> flip())

fun test-list() // Just like test-vector but for lists
   with handler
     ctl flip()
       val v1 = resume(True)
       val v2 = resume(False)
       return v1.append(v2)
   with return(v) [v]
   list(0, 4, fn(i) -> flip())

fun main()
   val vs = test-vector()
   // val vs = test-list()
   println(vs.length())
   vs.foreach(fn(v) print(v.length()))
   return ()

The expected behaviour is that test-vector should return 2^5 vectors of length 5 (containing all possible combinations of True and False elements in a 5-element vector) -- just like the test-list function returns the corresponding lists. But in Koka 2.6.0, test-vector only returns two zero-element vectors.

TimWhiting commented 6 months ago

Ah, we would need an if yielding check in the hand written c code for this.

Also since vectors don't have copy on write semantics I don't think it is advisable to be using control effects in general with this API. We should probably document better how vectors should be used and what to consider. But we probably should allow for exceptions.

TimWhiting commented 6 months ago

I'm wondering whether this would be an appropriate solution @daanx:

// Create a new vector of length `n`  with initial elements given by function `f` .
pub fun vector-init( ^n : int, f : int -> e a ) : e vector<a>
  val v = unsafe-vector(n)
  forz( 0.ssize_t, n.ssize_t ) fn(i)
    unsafe-assign(v,i,f(i.int))
  v
daanx commented 5 months ago

Thanks so much! Fixed now.