> My only complaint is that all functions are pure functions; there is not a way (that I know of) to share state from one function invocation to the next.
Indeed user-defined functions are pure. You can work around it like the suiji package[1] does: have the function return a value that you pass as argument to the next call.
[1] Random number generator in Typst: https://typst.app/universe/package/suiji/