type stream = SCons of int * (int -> stream)

let stream_first : stream -> int =
    fun st : stream ->
        match st with SCons hd thunk -> hd
in
let stream_rest : stream -> stream =
    fun st : stream ->
        match st with SCons hd thunk -> (thunk 0)
in

let make_stream : int -> (int -> stream) -> stream =
    fun (hd : int) (thunk : (int -> stream)) ->
        SCons (hd, thunk)
in

let stream_unfold : stream -> (int * stream) =
    fun st : stream ->
        (stream_first st, stream_rest st)
in

let stream_get : stream -> int -> int =
    fun (st : stream) (i : int) ->
        let acc : vec[stream] = vector 1 st in
        (for k = 0 to i do
            vector_set acc 0 (stream_rest (vector_get acc 0)) ;
            0
        done) ;
        stream_first (vector_get acc 0)
in

let rec count_from : int -> stream =
    fun n : int ->
        make_stream n (fun m : int -> (count_from (1 + n)))
in

let rec sift : int -> stream -> stream =
    fun (n : int) (st : stream) ->
        let hd : int = (stream_first st) in
        if (hd mod n) = 0 then
            sift n (stream_rest st)
        else
            make_stream hd (fun m : int -> (sift n (stream_rest st)))
in

let rec sieve : stream -> stream =
    fun st : stream ->
        let hd : int = stream_first st in
        make_stream hd (fun m : int -> (sieve (sift hd (stream_rest st))))
in

let primes : stream = sieve (count_from 2) in

let run_benchmark : int -> int = fun _ : int ->
    let n_minus_one : int = read_int () in
    print_int (stream_get primes n_minus_one) ;
    0
in
time run_benchmark
