Search code examples
functionprimessmlsmlnjsieve-of-eratosthenes

SML Sieve of Eratosthenes


I am new to SML. I am trying to create a function that outputs a list of all prime numbers which are smaller than or equal to a given integer n > 2 using the Sieve of Eratosthenes. I am running into a problem however where the output is only showing as [1]. I would like to be able to have an input such as 5 and get [1,3,5] as a result.

This is my code so far, I am very new so I know it is most likely not written correctly.

fun createList(ending) =
  let 
    fun createListX(start, ending) =
      if start = ending then []
      else start :: createListX(start + 1, ending)
  in
    createListX(1, ending + 1)
  end;

fun removeMult ([], n) = []
  | removeMult (x::xs, n) = 
      if x mod n = 0 then 
        removeMult(xs, n)
      else 
        x :: removeMult(xs, n);

fun sieve([], primes) = primes
  | sieve(n::ns, primes) = sieve(removeMult(ns, n), n :: primes);

fun dosieve(n) = sieve(createList(n-1), []);


Solution

  • Your removeMult function works nicely.

    Your sieve function works perfectly too. Too perfectly.

    Consider what happens when you call dosieve(10) for instance:

    dosieve(10)
    sieve(createList(9), [])
    sieve([1,2,3,4,5,6,7,8,9], [])
    

    From there:

    sieve(removeMult([2, 3, 4, 5, 6, 7, 8, 9], 1), 1 :: [])
    sieve([], [1])
    [1]
    

    Oops. You removed all multiples of 1, but of course they're all multiples of 1.

    Perhaps something like:

    fun sieve([], primes) = primes
      | sieve(1::ns, primes) = sieve(ns, 1 :: primes)
      | sieve(n::ns, primes) = sieve(removeMult(ns, n), n :: primes);