Your function add_spaces uses foldr in a beautifully convoluted but likely misunderstood way.
A regular recursive function, which won't satisfy the criterion of using foldl/foldr/map, is,
fun add_spaces [] = ""
| add_spaces [s] = s
| add_spaces (s::ss) = s ^ " " ^ add_spaces ss
A similar function relying on folding for its recursion would follow a pattern,
fun add_spaces [] = ""
| add_spaces (s1::ss) = fold<l/r> (fn (s,res) => ...) s1 ss
where ... explicitly does not refer to add_spaces. Thus, you have at least two instruments to guide the order in which your items arrive. One being the order in which you refer to s and res inside the anonymous function in the above template, and the other being your choice of foldl and foldr.
Notice also that foldl and foldr will traverse the list from different directions; from the left and from the right, respectively. To illustrate the order, try and fold with something that results in side-effects and see which effects arrive first:
- foldl (fn (s, _) => print (s^"\n")) () ["Hello", "World!"];
Hello
World!
> val it = () : unit
- foldr (fn (s, _) => print (s^"\n")) () ["Hello", "World!"];
World!
Hello