Haskell Map Exception Skip

I have the following code that returns the length of the loop in a string:

module Main where
import Data.List

detec ys n | 2*n > (length ys) = error "no cycle"
           | t == h = (2*n - n)
           | otherwise = detec ys (n+1)
            where
                t = ys !! n
                h = if n == 0 then ys !! 1 else  ys !! (n*2)
f x = detec (show x) 0
answer = map f [1/x|x<-[1..100]]

But what I don’t know how to do is ignore the exception "no cycle", so the generated list only contains the lengths of the lines, which are circular.

How can i do this?

+3
source share
3 answers

Please do not use errorto implement logic where an “erroneous” result is expected.

Instead, why not return Maybe ninstead of just nand then usecatMaybesNothing s to filter ?

The changes are quite simple:

module Main where
import Data.List
import Data.Maybe

detec ys n | 2*n > (length ys) = Nothing
           | t == h = Just (2*n - n)
           | otherwise = detec ys (n+1)
            where
                t = ys !! n
                h = if n == 0 then ys !! 1 else  ys !! (n*2)

f x = detec (show x) 0
answer = catMaybes $ map f [1/x|x<-[1..100]]

, ; , 2*n + 1 > length ys? , , !! length , , . - cons, , , . - , , , f (x:xs) = ....

+23

Project Euler # 26?

, , , : , 334/999 = 0.334334334 & hellip;, (3), (334). , , : № 26 , .

. , , , , .

findCycle :: Eq a => [a] -> Int
findCycle = findCycle' [] where
    findCycle' _ [] = 0
    findCycle' k (x:xs) = maybe (findCycle' (x:k) xs) succ $ elemIndex x k

: . ​​.

findCycle :: Eq a => [a] -> Int
findCycle xs = findCycle' xs (tail xs) where
    findCycle' (x:xs) (y:_:ys)
      | x == y = fromJust (elemIndex x xs) + 1
      | otherwise = findCycle' xs ys

, . , , .

+5

catch Control.Exception

import Prelude hiding (catch)
import Control.Exception

main = do
  print answer `catch` errorMessage
  where
    errorMessage :: SomeException -> IO ()
    errorMessage = putStrLn . ("error: " ++) . show

SomeException , :

[error: No cycle

, . .

Maybe , . MonadError:

{-# LANGUAGE FlexibleContexts #-}

import Control.Applicative
import Control.Monad.Error

detec2 :: (MonadError String m, Eq a) => [a] -> Int -> m Int
detec2 ys n | 2*n >= (length ys) = throwError "No cycle"
            | t == h = return (2*n - n)
            | otherwise = detec2 ys (n+1)
             where
                 t = ys !! n
                 h = if n == 0 then ys !! 1 else  ys !! (n*2)

( , , !! .)

, , :

answer2 = f2 <$> [1/x | x <- [1..100]]

f2 x = detec2 (show x) 0

main = do
  forM_ answer2 $
    \x -> case x of
            Left msg -> putStrLn $ "error: " ++ msg
            Right x  -> print x

error: No cycle
error: No cycle
2
error: No cycle
error: No cycle
3
6
error: No cycle
2

, - : IO. ,

cycles :: [Int]
cycles = [x | Right x <- answer2]

If you do not care about error messages at all, do not create them. The natural way to do this is with a list in which you return an empty list without loops and condense the result with concatMap:

detec3 :: (Show a) => a -> [Int]
detec3 x = go 0
  where go :: Int -> [Int]
        go n
          | 2*n >= len = []
          |     t == h = [2*n - n]
          |  otherwise = go (n+1)
          where t = ys !! n
                h | n == 0    = ys !! 1
                  | otherwise = ys !! (n*2)
                len = length ys
                ys = show x

main = do
  print $ concatMap (detec3 . recip) [1..100]

Finally, you might be interested in reading 8 ways to report bugs in Haskell .

+3
source

Source: https://habr.com/ru/post/1730429/


All Articles