Search code examples
ponylang

Implementing the map function for a Pony array


I have been playing with Pony arrays to understand Pony better, and wanted to write the map function for any arrays.

I am talking about something like the standard map function most languages have nowadays for converting elements of collections, as in Clojure:

(map #(+ 1 %) [1 2 3]) ; => [2 3 4]

But I want it to actually modify the given array, not return a new one.

My current attempt so far runs into many errors due to capabilities:

// array is "iso" so I can give it to another actor and change it
let my_array: Array[U64] iso = [1; 2; 3; 4]

// other actor tries to recover arrays as "box" just to call pairs() on it
let a = recover box my_array end // ERROR: can't recover to this capability
for (i, item) in a.pairs() do
  // TODO set item at i to some other mapped value
  try my_array.update(i, fun(item))? end
end

Anyone knows how this can be done


Solution

  • Alright, took me a while, but I was able to get things working.

    Here's my basic understanding of what's going on (please correct me if I'm wrong)!

    The first step was to understand that we need to use aliases to change the capabilities of a variable in Pony.

    So, in order to make an iso variable useable as a box, one must alias it by basically, consuming it into another variable:

      let a: Array[U64] ref = consume array // array is "iso"
      for (i, item) in a.pairs() do
        try a.update(i, item + n)? end
      end
    

    This works!!

    One more problem I had was that I couldn't do much with the resulting Array[U64] ref. Can't pass it to anyone, for example.

    So I wrapped the whole thing into a recover block in order to end up with the same array, but as a val (immutable reference to the array) which is more useful as I can send it to other actors:

    let result = recover val
      let a: Array[U64] ref = consume array
      for (i, item) in a.pairs() do
        try a.update(i, item + n)? end
      end
      a
    end
    

    Now I can send result to anyone!