LoginSignup
5
2

More than 5 years have passed since last update.

Project EulerでF#の勉強をしました(Problem1~3編)

Last updated at Posted at 2018-06-21

はじめに

初心者プログラマです。
「関数型触ってみよう」だけのモチベーションで少し前からF#で遊んでいます。
とりあえず手元には1~10までやってあるので、そこまで記事にする予定です。

初投稿です。よろしくおねがいします。

ProjectEuler

数学(数字?)の問題をプログラムで解く課題がたくさん置いてあるところです。これです。↓
https://projecteuler.net/

日本語翻訳版wiki↓
http://odz.sakura.ne.jp/projecteuler/

早速やっていきます。
手元でしか動かしていないので、間違いがあったら指摘を頂けると喜びます。

Problem 1

10未満の自然数のうち, 3 もしくは 5 の倍数になっているものは 3, 5, 6, 9 の4つがあり, これらの合計は 23 になる.
同じようにして, 1000 未満の 3 か 5 の倍数になっている数字の合計を求めよ.

let rec sum xs =
    match xs with
    | [] -> 0
    | y::ys -> y + sum ys

let filter pred xs =
    let rec inFilter xs =
        match xs with
        | [] -> []
        | y::ys -> if pred y then y::inFilter ys else inFilter ys
    inFilter xs

let Problem1 = [1..999] |> filter (fun x->(x%3 = 0)||(x%5 = 0)) |> sum

勉強なので、車輪の再開発はどしどししていきます。
特に言うことはない気がしますが、
再帰で足し算をするやつsumと再帰でlist要素抽出をするやつfilterに[1..999]を突っ込んでいます。

Problem 2

フィボナッチ数列の項は前の2つの項の和である. 最初の2項を 1, 2 とすれば, 最初の10項は以下の通りである.
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
数列の項の値が400万以下の, 偶数値の項の総和を求めよ.

let returnFibList lim =
    let rec inReturnFibList ns n0 n1 =
        match n1 with
        | _ when n1 < 2 -> inReturnFibList [] 1 2
        | _ when n1 >= lim -> ns
        | _ -> inReturnFibList (ns@[n1]) n1 (n0+n1)
    inReturnFibList [] 1 2

let Problem2 = returnFibList 4000000 |> filter (fun x -> x%2 = 0) |> sum

フィボナッチ数列を下から求めましたが、変な事ではないですよね・・・?(不安)
400万まで求めて、またfilter、sumですね。
Cとかばっかりやっていたので、filter関数だけで感動しているフシがあります。

それから、この後も続きますが、勉強した流れからか基本的に継続渡しで再帰を作っています。

Problem 3

13195 の素因数は 5, 7, 13, 29 である.
600851475143 の素因数のうち最大のものを求めよ.

let SieveOfEratosthenes (max:int64) =
    let rtMax = (float >> sqrt >> int64 <| max)
    let rec inSieveOfEratosthenes ps ns =
        match ns with
        | [] -> ps
        | head::body when head > rtMax -> ps@body
        | head::body -> inSieveOfEratosthenes (ps@[head]) (filter (fun x -> (x % head <> 0L)) body) 
    inSieveOfEratosthenes ([]:int64 list) [2L..max]

let findLargestPrimeFactor (target:int64) =
    SieveOfEratosthenes target |> filter (fun (x:int64) -> (target % x = 0L))

let rec max64 (xs:int64 list) =
    match xs with
    | [] -> 0L
    | [y] -> y
    | y::ys ->
        match ys with
        | [z] -> if y > z then max64 [z] else max64 [y]
        | z::zs -> if y > z then max64 (y::zs) else max64 (z::zs)
        | [] -> 0L

let Problem3 = findLargestPrimeFactor 600851475143L |> max64

SieveOfEratosthenes(エラトステネスのふるい)で素数リストを作って、
対象(600851475143)を割り切れる値(=素因数)抽出して、
そのリストの最大値を選んでいます。

型まわりの書き方がわかっておらず「とりあえず全部int64にするか・・・」などとしてしまっています。
そのためにmax関数もint64用を再開発。恥ずかしい事をしていたらどうしよう。

最大の難所はlet rtMax = (float >> sqrt >> int64 <| max)のくだりでした。
「floatにしてsqrtかけてint64にするのを合成した関数にmaxを渡す」という理解ですが、
正直なところググり知識が元なので、別の形に応用して使っていけるかがまだ怪しいところです。
パイプラインをmax|>にするとエラーになる理由とかがよくわかってないのでたぶんダメですね・・・。

おわり

Problem10まで続きます。(投稿したらリンクを貼りに来ます。)→貼りに来ました
(Problem4~5編)
(Problem6~7編)
(Problem8~10編)

ご指導してくださる方がいらっしゃれば、よろしくお願い致します。

5
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2