What you describe is, as you comment yourself, map
:
val uppercase = String.map Char.toUpper
val uppercaseMany = List.map uppercase
You should pick map
when it most accurately describes what you're doing, since it conveys the intent of your code faster.
map
does something more specific than foldl
, since map
can only always return a list with the same number of elements as its input, where each element has been transformed in exactly the same way and independent of the other functions (at least to the extent of map
's own accord).
In fact, map
is a special case of foldr
since you can implement map
using foldr
but not the other way around:
fun map f = foldr (fn (x, xs) => f x :: xs) []
foldl
and foldr
can reduce a list of things to anything, e.g. a tree:
datatype 'a binaryTree = Leaf | Branch of 'a * 'a binaryTree * 'a binaryTree
fun insert (x, Leaf) = Branch (x, Leaf, Leaf)
| insert (x, Branch (y, left, right)) =
if x <= y then Branch (y, insert (x, left), right)
else Branch (y, left, insert (x, right))
val listToTree = foldl insert Leaf
I picked foldl
and foldr
conveniently, but you can also express one using the other.
The idea of folding can work on any tree structure, not just lists. Here's a StackOverflow answer on how to fold binary trees, and here's a StackOverflow Q&A on Tail-recursion on trees.