So I was playing with the idea of a 2D array. Started a base implementation but it is starting to feel like a round peg square hole, I suspect it is my imperative design sensibilities not fitting. I was wondering if anyone has advice for either making this idea follow "idiomatic" roc. Or maybe this should be something provided by a platform? I would be kind of interested in a platform that provided tools for things like this. I did see there is an array2d package for the old compiler but I am hoping to bang my head against this for a bit first.
Array := {
data : List(F64),
rows : U64,
cols : U64,
stride : U64,
}.{
init: U64, U64 -> Array
init = |rows, cols| {
return {
data: Math.linspace(0, (rows * cols).to_f64(), (rows * cols).to_i64_wrap()),
rows: rows,
cols: cols,
stride: cols,
}
}
get = |arr, i,j| {
return arr.data.get(i * arr.cols + j)
}
set! = |arr, i,j,x| {
newData = arr.data.update(i * arr.cols + j, |_| x)?
return Ok({ data: newData, rows:arr.rows, cols: arr.cols, stride:arr.stride})
}
}
You might as well expose a NdArray with shape instead of rows and cols. However roc does not have the machinery to implement efficient numerical computation ops. So you’ll have to call into a plateform that does it instead of roc. I would suggest rust burn https://github.com/tracel-ai/burn. If you can target their backend agnostic IR that will give you the most flexibility on how to design the roc API. Then when Mojo goes open source supposedly sometime this year it should be possible to build mojo platforms, in which case a MAX powered plateform would give you SoTA performance
That looks pretty good in my opinion @Timothy Daniel.
Note that you never need to use return on the last line of a block in Roc.
Regarding the performance, it will not squeeze every drop out of your hardware but it will (probably) not be slow either.
Last updated: Jul 23 2026 at 13:15 UTC