I recently started with F# and implemented a very basic recursive function that represents the Sieve of Eratosthenes. I came up with the following, working code:
static member internal SieveOfEratosthenesRecursive sequence accumulator =
match sequence with
| [] -> accumulator
| head::tail -> let rest = tail |> List.filter(fun number -> number % head <> 0L)
let newAccumulator = head::accumulator
Prime.SieveOfEratosthenesRecursive rest newAccumulator
This function is not really memory efficient so I tried to eliminate the variables “rest” and “newAccumulator”. I came up with the following code
static member internal SieveOfEratosthenesRecursive sequence accumulator =
match sequence with
| [] -> accumulator
| head::tail -> tail |> List.filter(fun number -> number % head <> 0L)
|> Prime.SieveOfEratosthenesRecursive (head::accumulator)
As far as I understand the tutorials I’ve read Prime.SieveOfEratosthenesRecursive will be called with the filtered tail as first parameter and a list consisting of head::accumulator as second one. However when I try to run the code with the reduced variable usage, the program gets trappen in an infinite loop. Why is this happening and what did I do wrong?
You have this backwards.
In the first version, you’re passing
restthennewAccumulator; in the second version, you’re effectively passingnewAccumulatorthenrest. I.e., you’ve transposed the arguments.Prime.SieveOfEratosthenesRecursive (head::accumulator)is a partial function application wherein you’re applying(head::accumulator)as the first argument (sequence). This partial function application yields a unary function (expectingaccumulator), to which you are passing (via|>) what is calledrestin the first version of your code.Changing
SieveOfEratosthenesRecursive‘s argument order is the easiest solution, but I would consider something like the following idiomatic as well:or
FWIW, eliminating
restandnewAccumulatoras named variables here is not going to impact your memory usage in the slightest.