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モナドっぽく使うためなんですかね。