http://projecteuler.net/index.php?section=problems&id=3
最大の素数を求めればよいのですが、せっかくなので素因数分解のコードを書きました。あまりうまく書けていません。
let rec calc_exp n p = if n % p = 0 then let t = calc_exp (n / p) p (fst t + 1, snd t) else (0, n) let rec fac n p = if n = 1 then [] else if p * p > n then [(n, 1)] else let t = calc_exp n p if fst t > 0 then (p, fst t) :: (fac (snd t) (p + 1)) else fac n (p + 1) let factorize n = fac n 2 let f = factorize 13195 printfn "%d" (fst (f.[f.Length-1]))
ここも3タブにしています。
リストのインデックス参照は、
list.[index]
とします。
上は例題を解いていますが、このまま問題にあてはめると、
let f = factorize 600851475143
32ビット整数の範囲外と怒られてしまいました。Haskellのように適当に判断してくれません。サフィックスがない整数は32ビット整数とみなされます。64ビット整数を使いたい場合はサフィックスLをつけます。
let f = factorize 600851475143L
しかしこれだとintのはずがint64だと怒られます。どうやらCなどと違って勝手に型変換はしてくれないようです。必要なところはint64にしなければなりません。片っ端からLをつけて、
let rec calc_exp n p = if n % p = 0 then let t = calc_exp (n / p) p (fst t + 1, snd t) else (0, n) let rec fac n p = if n = 1L then [] else if p * p > n then [(n, 1)] else let t = calc_exp n p if fst t > 0 then (p, fst t) :: (fac (snd t) (p + 1L)) else fac n (p + 1L) let factorize n = fac n 2L let f = factorize 600851475143L printfn "%d" (fst (f.[f.Length-1]))
まだ型が合わないとコンパイラに怒られます。こういうときコンパイラは大抵的外れところを指摘して、本当に間違っているところはわかりません。
こういうときの定番の解決方法は型を指定することです。型指定しなくても型推論で型を決めてくれるはずなのですが、コードのどこかが間違っていると意図していない型に解釈される可能性があります。これを排除するために型を指定します。例えば、
let f n = n + 1
は引数と戻り値の型を書くと、
let f (n : int) : int = n + 1
となります。intは32ビット符号付き整数です。64ビット版はint64です。ここで、素因数分解の結果はint64(素数)とint(指数)のタプルのリストで返すようにしています。タプルの型は、
int64 * int
と表します。タプルは直積を意味するみたいな感じでしょうか。そしてリストは、
(int64 * int) list
です。型を元のコードにいくつか付けてみてコンパイルしたところ次のようなエラーメッセージが出ました。
euler003.fs(2,15): error FS0001: This expression was expected to have type int64 but here has type int
2行目の15文字目、
if n % p = 0 then
0にLがついていなかったんですね。これで正しく答えが出ます。
let rec calc_exp (n : int64) (p : int64) : int * int64 = if n % p = 0L then let t = calc_exp (n / p) p (fst t + 1, snd t) else (0, n) let rec fac n p : (int64 * int) list = if n = 1L then [] else if p * p > n then [(n, 1)] else let t = calc_exp n p if fst t > 0 then (p, fst t) :: (fac (snd t) (p + 1L)) else fac n (p + 1L) let factorize (n : int64) : (int64 * int) list = fac n 2L let f = factorize 600851475143L printfn "%d" (fst (f.[f.Length-1]))