http://projecteuler.net/index.php?section=problems&id=2
フィボナッチ数列を次のように定義すると、
let fib = seq { let mutable a = 1 let mutable b = 1 while true do yield b let tmp = b b <- a + b a <- tmp }
mutableは使えないと怒られてしまいました。ここは参照を使うべきところのようです。平方を出すコードなら、
let sq = seq { let i = ref 0 while true do yield !i * !i i := !i + 1 } printfn "%A" (Seq.toList (Seq.take 5 sq))
意味はコードを見ればわかるでしょう。
結局フィボナッチ数列は、
let fib = seq { let a = ref 1 let b = ref 1 while true do yield !b let tmp = !b b := !a + !b a := tmp } let N = 4000000 printfn "%d" (Seq.sum (Seq.filter (fun n -> n % 2 = 0) (Seq.takeWhile (fun n -> n <= N) fib)))
長たらしくなってしまいました。(インデントはこれでいいんだ。昨日のはなんだったんだ?)
実はunfoldという関数を使えば簡単に書けます。unfoldは、
Seq.unfold f 状態0
とすると、
状態0 -> f(状態0) = (値1, 状態1) -> f(状態1) = (値2, 状態2) -> …
と計算していき、
seq [ 値1; 値2; … ]
が返るという関数のようです(実際には遅延評価と思われる)。これは便利ですね。
let fib = Seq.unfold (fun t -> Some(snd t, (snd t, fst t + snd t))) (1, 1) let N = 4000000 printfn "%d" (Seq.sum (Seq.filter (fun n -> n % 2 = 0) (Seq.takeWhile (fun n -> n <= N) fib)))
takeWhileもふつうに使えます。
SomeってついているのはMayBeモナドっぽく使うためなんですかね。