unfoldr ← iterate
勉強会で unfoldr を教わったので、unfoldr 厨になってみる。
どこに使えるかなと考えてみて、種からリストを生成してるんだから iterate と同じじゃん!と思って、26問目を書き換えてみました。
もともとのコード。「ウサギとカメ」です。
cyclePart :: [Int] -> [Int] cyclePart xs | (t' == 0) = [] | otherwise = t' : (takeWhile (/= t') $ map fst ys) where ((t', r') : ys) = dropWhile (\ (t, r) -> t /= r) $ zip xs $ map head $ iterate (drop 2) $ tail xs rems :: Int -> [Int] rems n = iterate next 1 where next rem = mod (rem * 10) n
で、iterate を使ってる2ヶ所を unfoldr にしてみたコード。有限のリストは有限のリストとして扱っているので、こっちの方が厳密ですね。
case と if のどちらを使うかとか、しょうもないことで悩んでしまった。
cyclePart :: [Int] -> [Int] cyclePart xs = case map fst $ dropWhile (\ (t, r) -> t /= r) $ zip xs $ unfoldr phi xs of [] -> [] (y:ys) -> y : takeWhile (/= y) ys where phi ys = case drop 1 ys of [] -> Nothing (z:zs) -> Just (z, zs) rems :: Int -> [Int] rems n = unfoldr phi 1 where phi r = let m = mod (r * 10) n in if m == 0 then Nothing else Just (m, m)