Project Euler 2(1)

http://projecteuler.net/index.php?section=problems&id=2


Haskellで書くと、

fib = 1:2:[ a + b | (a,b) <- zip fib (tail fib) ]
main = print (sum (takeWhile (<=4*10^6) (filter even fib)))

フィボナッチ数列の無限リストを作ってtakeWhileでぶった切るのが定番の解法です。
F#でリストでは無限リストは実現できない、のかな?代わりにSequenceというものを使うと無限リストのようなものができます。

let sq = Seq.initInfinite (fun i -> i * i)
printfn "%A" (Seq.toList (Seq.take 5 sq))   // "%A"はList用のformat

これを実行すると、

[0; 1; 4; 9; 16]

Seq.initInfiniteの引数に0,1,2,...と適用したときの無限リストが作られるらしいです。Seq.takeで頭の5つを取って、Seq.toListでリストに変換して、"%A"で出力します。
けれど、これはフィボナッチ数列には使いにくいですよね。もう一つPythonのようなyieldを使う方法があります。

let count = Seq.initInfinite (fun i -> i)
let sq = seq {
    for i in count do
        yield i * i
}

printfn "%A" (Seq.toList (Seq.take 5 sq))

コンパイラにタブ使うなと怒られてしまいました。試行錯誤を繰り返した結果、

let count = Seq.initInfinite (fun i -> i)
let sq = seq {
   for i in count do
   yield i * i
}

printfn "%A" (Seq.toList (Seq.take 5 sq))

どうやら、インデントはスペース3つ以内で{}内は揃える、ということのようです。エディタの設定で拡張子.fsなら3タブでタブで空白入力ということにしましょうかね。
タブを使いたければソースの頭に次のように書くとよいようです。

#light "off"

let count = Seq.initInfinite (fun i -> i)
let sq = seq {
    for i in count do
        yield i * i
    done
};;

printfn "%A" (Seq.toList (Seq.take 5 sq))

こうするとインデントを揃えるなどはしなくてよいようです。ただし、適切に;;を入れたりループの終わりにdoneを入れたりと色々面倒なようです。
長くなったので今回はここまでにします。