ふるい〜ふるかね〜

某日記インスパイヤされて
無限リストを書いてみた。OCamlで。

open Lazy
type 'a inf_list = {
  hd : 'a;
  tl : 'a inf_list Lazy.t;
}
let hd x = x.hd and tl x = force(x.tl)

let rec primes_from_2 = { hd = 2; tl = lazy(primes_from 3) }

and primes_from n =
  if is_prime n then { hd = n; tl = lazy(primes_from (n+1)) }
  else primes_from (n+1)

and is_prime n =
  let rec iter n x =
    let m = hd x in
    m*m > n || n mod m != 0 && iter n (tl x)
  in
  iter n primes_from_2

コンパイルできるのが不思議なくらいだ。
動作チェックは

let test_print =
  let a = ref primes_from_2 in
  let p = ref(hd !a) in
  while !p < 1000000 do
    Printf.printf "%d\n" !p;
    a := tl !a;
    p := hd !a;
  done

とでも。


追記: 試しにhaskell書いてみた。みじけぇ。。。

primes :: [Integer]
primes = 2 : primes_from 3
  where primes_from n = if prime_test n primes then n : primes_from (n+1)
                        else primes_from (n+1)
        prime_test n (hd:tl) = hd*hd > n || mod n hd /= 0 && prime_test n tl

ただ、ウィソのghciで試した限りでは&&と||を使うより
if then elseを使うほうが断然速いという罠。