I can build a data structure that is a member of the Traversable typeclass (e.g. List or Map), by mapping (map, mapM) or folding (foldl, foldM) another traversable data structure.
However, I often encounter situations where I need to build a traversable data structure with a member of the Num typeclass (e.g. Integer).
My usual approach here is to build a list by using a recursive operation - for example:
foo :: Integer -> [Integer] -> [Integer]
foo n fs
| m < 2 = fs
| rem m 2 == 0 = foo (m - 1) (m:fs)
| otherwise = foo (m - 1) fs
where m = abs n
This function returns the absolute values of the integers that are divisible by two, and are between 2 and n (inclusive).
Using the above example, is there an idiomatic way to build a list from a non-traversable without using recursion?
You're asking for a way to build a list from a non-traversable object without using recursion, but I don't think this is really what you want. After all, any traversal is going to use recursion — how do you think
mapandfoldlare implemented? I think the more precise question you're asking is whether there's a well-known function or built-in way to express a so-called "numeric fold" where the recursion is "behind the scenes", or implicit, instead of explicit as in yourfooexample.Well, one simple way to achieve this is to write a
foldNumfunction yourself. For instance:Then, you can define
fooas:If you're a little disappointed with this, I understand why: you haven't really saved much by using this definition of
foldNum. In fact, the definition I give above doesn't even have a built-in base case. The problem with folding a number is that there are lots of ways to do it! You can subtract or add any amount on each step, and there's no clear place to stop (zero might seem a natural place to stop, but that's only true for non-negative numbers). One way to proceed is to try to make ourfoldNumeven more generic. How about:Now, we can write
fooas:Maybe this is what you're looking for?
Footnote: Just as lists can be folded left or right (
foldlandfoldr), soo too can we fold numbers in two different ways. You can see this by replacing the last line of the abovefoldNumdefinition with::For instance, for
foothe difference between these two is the order of the resulting list.