2

そこで、Haskell をいじってみることにしました。Project Euler の最初の問題を解決しようとしています。以下は私のコードです:

     euler1 limit (div:divisors) = if limit > 1 then (euler1 limit divisors) + (euler1 limit (div:[])) + (euler1 (limit-1) (div:divisors)) else 0
     euler1 limit (divisor:[]) = if limit > 1 && (mod limit divisor) == 0 then limit else 0
     euler1 limit [] = 0

ただし、これを ghci で実行すると、次のようになります。

     euler1 9 [3,5]
     *** Exception: <interactive>:3:5-90: Non-exhaustive patterns in function euler1

さらなるデバッグ:

     euler1 5 []
     0

     euler1 5 [5]
     *** Exception: <interactive>:3:5-90: Non-exhaustive patterns in function euler1

これは、壊れたコードが euler1 に再帰ステップさえ含まれていない 2 番目のケース (要素が 1 つのリスト) にあることを示唆しています。

どうしたの?なぜこれほどまでに見事に割れているのでしょうか。私が見逃したパターンは何ですか?(単一要素リスト、複数要素リスト、空のリストはありませんか?)

編集:私が最初に上で提供した解決策を気にする人にとっては(John Lsの素晴らしい助けを借りて)、1つ以上の約数の倍数であるアイテムを2回以上カウントするため、まだ正しくありません。最終的な、正しく動作するアルゴリズムは次のとおりです。

       euler1 limit (divisor:[]) = if ((limit > 1) && ((mod limit divisor) == 0)) then limit else 0
       euler1 limit (div:divisors) | ((limit > 1) && (euler1 limit (div:[]))==0) = (euler1 limit divisors) + (euler1 (limit-1) (div:divisors)) | ((limit > 1) && (euler1 limit (div:[]))/=0) = (euler1 limit (div:[])) + (euler1 (limit-1) (div:divisors)) |limit > 1 = euler1 (limit-1) (div:divisors) | otherwise = 0
       euler1 limit [] = 0
4

1 に答える 1

10

これをghciで定義していますか?もしあなたがそうするなら:

Prelude> let euler1 limit (divisor:[]) = if limit > 1 && (mod limit divisor) == 0 then limit else 0
Prelude> let euler1 limit [] = 0

2 番目の定義は最初の定義を覆い隠し、非網羅的なパターン エラーを引き起こします。

代わりに、ghci の複数行構文を使用する必要があります。

Prelude> :{
Prelude| let euler1 limit (divisor:[]) = if limit > 1 && (mod limit divisor) == 0 then limit else 0
Prelude|     euler1 limit (div:divisors) = if limit > 1 then (euler1 limit divisors) + (euler1 limit (div:[])) + (euler1 (limit-1) (div:divisors)) else 0
Prelude|     euler1 limit [] = 0
Prelude| :}

また、上の 2 つのステートメントの順序を入れ替えたことにも注意してください。div:divisorsは単一要素のリストに一致するため、最初にその特殊なケースを確認する必要があります。

于 2013-02-08T07:00:48.457 に答える