自分自身を除く、約数の和が、自分自身と等しい自然数を、完全数と呼びます。
ここでは、指定した自然数の範囲の中で、この完全数を探し出す関数を定義します。
とはいいつつも、この要件を満たすために必要なステップを洗い出す必要があって、
いくつか段階を踏まないといけません。
全体の筋書きは、こんな感じですかね。
関数perfects
perfects :: Int -> [Int]
perfects n = [x | x <-[1..n], perfect x == True]
関数perfectsを定義し、
その中で、与えられた数が完全数か否か?を判定する関数perfectを呼び出す。
結果をリストで返す。
んで、次は、関数perfectを定義してみます。
関数perfect
perfect :: Int -> Bool
perfect n = sum list == n
where list = dropMostR(factors n)
この関数の中で、与えられた数の約数達のリストを算出するfactors、
そして、約数のリストから、与えられた数を除き、リストとして返す、dropMostRを
呼び出しています。
んで、約数のリスト要素を関数sumを利用し合算、結果を与えられた数と比較し、
完全数か否かを判定した結果であるブール値を返す関数動作を定義しています。
んじゃ、次に、関数factorsの定義
関数factors
factors :: Int -> [Int]
factors n = [x | x <- [1..n], n `mod` x == 0]
単純に、約数のリストを算出する定義です。
ついで、関数dropMostRの定義
関数dropMostR
dropMostR :: [a] -> [a]
dropMostR (x:xs)
| length(xs) == 0 = []
| otherwise = x : dropMostR(xs)
こいつは、再帰を使って、リストの要素をぐーるぐる、トラバースして、
一番最後の要素を除いた形で、リストを作成しています。
↑をまとめると、こんな感じの定義となります。
find-perfect.hs
factors :: Int -> [Int]
factors n = [x | x <- [1..n], n `mod` x == 0]
dropMostR :: [a] -> [a]
dropMostR (x:xs)
| length(xs) == 0 = []
| otherwise = x : dropMostR(xs)
perfect :: Int -> Bool
perfect n = sum list == n
where list = dropMostR(factors n)
perfects :: Int -> [Int]
perfects n = [x | x <-[1..n], perfect x == True]
ちなみにこの関数を自然数1〜9000の間で実行したら、
perfects 9000
[6,28,496,8128]
という結果を得ます。
この人達、wikiに載ってる完全数の一覧どおりなのです。