Does rescript have iterator constructs?

Looking at the docs it only seems like rescript has the ability to iterate over ranges, is there any way to define custom iterators? Or just iterate over the contents of an array?

I’m not sure what you are trying to do exactly.

For arrays, there are:

  • Belt.Array.map: you provide an array and a “map function”, you get a new array containing the “mapped” elements (result of the map function applied to every element of the input array
  • Belt.Array.forEach: similar to above, the “map function” needs to return unit (aka is doing some side effects), it finally returns unit

There are also other functions with similar names in Belt.Array having slightly different types.

let x = ["hello", "hi", "hola"]

// Note: y is a new array, x won't be modified
let y = x->Belt.Array.map(el => el ++ " world")

y->Belt.Array.forEach(el => Js.log(el))

Try on the playground

1 Like

It might be that I’m just too used to thinking in terms of other languages that have either traits or some form of polymorphism which I’m guessing rescript doesn’t have?

Like if I’m designing a custom container and I wanted it to implement foreach I just write a forEach implementation for it in rescript? I can’t go and pass that to a function that takes any iterator though right?

Rescript has polymorphism, but it seems not in a way you are used to…

  • function overloading is not supported: a function (“name”) has exactly one type signature.
  • most commonly are type parameters used, like array<'a>, when you don’t care about the actual “container’s content”
  • edit: there are other ways as well, which I’m not going into here

It depends on how you define an iterator in the language you are working in…
If you are familiar with “type classes” or “category theory”: Rescript has functors. Which are “higher order functions” taking one or several modules as arguments and returning a new module. Heavy functor usage doesn’t translate well to compiled js, therefore it’s discouraged
But there are still applications for it.

In your example, you could define a module type specifying functions needed any module needs to provide to be iterable. A functor could then be implemented which takes any module according to this type and returns functions like forEach, map etc.

The reason why most of the builtin types have their own functions is, that they are essentially bindings to their js counterparts. Therefore a common iterable interface is unnecessary there.

See Implementing the iterable protocol (Symbol.iterator) - #5 by kevinbarabash for previous discussion about iterators.

It’s possible to set up JavaScript iterators today, both sync and async. But it’s a bit messy and rather unsafe. We’ve got some iterator related bindings in ReScript Core. If there’s interest, I’m sure we could add Iterator.make/AsyncIterator.make for creating JS iterators, hiding the creation behind a type safe interface. Feel free to open an issue on the repo if that’s of interest.

1 Like