I'm looking to generate a list of powers in Elm, up to a certain limit. I've written the following tests:
[ test "works for negative limit" <| \_ -> equal (powers 2 -5) (Ok ) , test "works for 2 up to 63" <| \_ -> equal (powers 2 63) (Ok [1, 2, 4, 8, 16, 32]) , test "works for 2 up to 64" <| \_ -> equal (powers 2 63) (Ok [1, 2, 4, 8, 16, 32]) , test "works for 3 up to 81" <| \_ -> equal (powers 3 81) (Ok [1, 3, 9, 27, 81]) , test "rejects negative bases" <| \_ -> equal (powers -2 63) (Err "negative base") ]
I have a solution that I'm not happy with because it seems pretty long. Now I know that when doing these kinds of things in the functional style, we generally use tail recursion (which is no problem). But as I am building up the list from small numbers to large numbers (e.g., 1 2 4 8 16 32 ...) I could keep appending to the accumulated list, but this is much slower than using prepend (
::). So... I decided to prepend and then reverse at the very end:
powers base limit = if base < 0 then Err "negative base" else let helper base exponent limit soFar = let next = base ^ exponent in if next > limit then Ok soFar else helper base (exponent + 1) limit (next :: soFar) in case helper base 0 limit  of Ok powerList -> Ok <| List.reverse powerList Err message -> Err message
This passes all the tests but I am wondering two things:
- Is consing (
::) and then reversing at the end the right way to do this or is there a better way?
- Is there something amazing in Elm's
Listmodule that I missed that I should be using here?
- At the very end, when I wanted to reverse, was it necessary to do that matching? It seems unnecessarily verbose because I had to pass through the whole
Errpart. Since I only wanted to reverse a list in the
Okcase and leave the
Errpart unchanged, was there a better way to write this?