LoginSignup
5
1

More than 5 years have passed since last update.

合成数列の和 in Haskell

Last updated at Posted at 2018-12-21

合成数列の和 Advent Calendarに、Haskellで参加してみました。

Haskellを選んだ経緯

少し前の日にC++版を上げましたが、いっときはテンプレートメタプログラミングを考えていました。ただ、書こうとしてのあまりのやりづらさに、結局「これで苦しむぐらいなら、同じく純粋関数型のHaskellで書いたほうがいい」という考えに至り、Haskellで書いてみることとしました。

とはいえ、Haskellでコードを書くのは初めてなので、すごいH本を片手に進めていくこととしました。

まずはコード

dividors :: [Int]
dividors = [2] ++ iterate (+2) 3

target :: Int -> [Int]
target x = takeWhile (\k -> k * k <= x) dividors

isComposite :: Int -> Bool
isComposite x = any (\k -> x `mod` k == 0) (target x)

composites :: [Int]
composites = [x | x <- [4, 5..], isComposite x]

compositeSum :: Int -> Int
compositeSum cnt = sum $ take cnt composites

main = do
    num <- readLn :: IO Int
    putStrLn $ show $ compositeSum num

Wandboxで動作確認

解説

無限リスト

Haskellは遅延評価なので、無限個のリストも扱うことができます。iterate (+2) 3で3から始まる無限の奇数列を作って、先頭に2を追加して試し割りするリストを作っておきます(素数列を作ればいいのですが、ぱっとそこまでたどり着くことはできませんでした)。

そして、targetで必要な分(平方根まで)を切り出しています。

リスト内包表記

[x | x <- [4, 5..], isComposite x]という短い式ですが、これだけで「4以上の整数から合成数だけ抜き出す」という意味になります。そして、この結果も無限リストのままなので、いくつでも必要なだけ抽出できます。

do記法

Haskellは純粋関数型言語である以上、そのまま入出力を扱うことはできません。モナドという仕組みを介しているのですが、do記法はそれを命令形言語のような見た目で書くことを可能としています。

おわりに

Haskellは初心者なので、改善点などありましたらコメントをいただければと思います。

5
1
1

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
1