2) They're not primitives. It's very much possible to build for and while loops from elements in the Haskell standard library, because you have more powerful primitives to work with. Most languages have loops as primitives.
Regular tail-recursion takes some getting used to coming from an imperative background, it’s arguably the fork point on whether someone is going to stick it out.
The whole time I'm wondering if I'm just writing Haskell "with a heavy Scheme accent", since I see others' Haskell code make extensive use of state monads (which I still haven't attempted to understand), and I also found others' using way more of the monadic / applicative operators like "bind", etc than I have.
I found the hard part of Haskell not the iteration, which from tail recursion was completely natural and straightforward, but rather worrying about the efficiency of the "repeatedly consing" part. For things like stacks, the cost is O(1), but for things like Data.Array, I wasn't sure how much shared structure there was; I mean it could totally be copying the entire array every time I "mutate" an element (not really, since it was still sort of "consing" onto the old array and not actually mutating it).
[1] https://github.com/xdavidliu/advent-of-code/blob/main/2016/d...