Вы можете использовать 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]
Если вам не нужны сообщения об ошибках, не генерируйте их. Естественный способ сделать это - использовать списки, в которых вы возвращаете пустой список без циклов и уплотняете результат с помощью 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]
Наконец, вам может быть интересно прочитать 8 способов сообщения об ошибках в Haskell .