4

私は Haskll を学ぼうとしているので、Haskell で Project Euler の質問 26 を試していました: http://projecteuler.net/problem=26

この問題に対する私の解決策は次のとおりです。

answer26 = answer26' 1000
answer26' n = snd $ maximum $ map (\x -> cycleLength x [1]) [2..n - 1]
    where
    cycleLength n (r:rs)
        | i /= Nothing      = (1 + fromJust i, n)
        | r < n             = cycleLength n $ (10*r):r:rs
        | otherwise         = cycleLength n $ (r `mod` n):r:rs
        where i = elemIndex r rs

これは最も効率的なアルゴリズムではないことを認識していますが、単純に O(n^3) (n = 1000) であるため、それほど問題ではありません。しかし、私が懸念しているのは、モナドに関する私の理解から、モナドを使用したものを何らかの意味で「マーク」するという主な特性の 1 つであるということです。関数「fromJust」は、それに直面して直接飛んでいるようです。なぜそれが存在するのですか?また、その存在が正当化されていると仮定すると、上記のコードでの私の使用法は適切ですか?

4

3 に答える 3

11

部分関数 (値を返さない可能性のある関数) の使用は、一般的にお勧めできません。関数headと同様の関数がfromJust存在するのは、それらが便利な場合があるためです。学習者にとってより理解しやすい短いコードを記述できる場合もあります。head関数型アルゴリズムの多くは、 およびtailで表現され、fromJust概念的には と同じheadです。

通常は、パターン マッチングを使用し、部分的な関数を回避することをお勧めします。これにより、コンパイラがエラーをキャッチできるようになるためです。コード スニペットでは、値が never であることを慎重に確認しましたNothingが、実際の大規模なコードベースでは、コードは何年も前のもので、数千行の長さで、多くの開発者によって維持されている可能性があります。開発者が一部のコードを並べ替えて、そのようなチェックを逃すのは非常に簡単です。パターン マッチングでは、任意の Bool 式だけでなく、コード構造の中にあります。

fromJustの使用法をパターン マッチングに置き換えることはそれほど難しくありません。

answer26 = answer26' 1000
answer26' n = snd $ maximum $ map (\x -> cycleLength x [1]) [2..n - 1]
    where
    cycleLength n (r:rs) = case elemIndex r rs of
            Just i  -> (1 + i, n)
            Nothing -> if r < n
                        then cycleLength n $ (10*r):r:rs
                        else cycleLength n $ (r `mod` n):r:rs

そして(私が思うに)結果も少し明確です。

編集: TypeclassopediafromJustで言及されているように見える「理論的には問題ない」使用場所がありますが、wtf について説明するには私以外の誰かが必要になります.. ;)

于 2013-08-17T13:10:37.923 に答える
3

このパターンは非常に一般的で、そのための関数もあります: Maybe :: b -> (a -> b) -> Maybe a -> b

あなたの場合、\x -> (cycleLength x [1], x) を実行すると、つまり、cycleLength の外側でペアを作成します。

    cycleLength n (r:rs) = maybe (cycleLength n rs') (1+) $ elemIndex r rs where
      rs'
        | r < n = (10*r):r:rs
        | otherwise = (r `mod` n):r:rs

また、実際の値ではなく最大値だけを探しているため、(1+) の代わりに id を使用しても機能します。

于 2013-08-18T11:09:55.987 に答える