Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell中使用映射时跳过异常_Haskell_Error Handling_Map - Fatal编程技术网

在Haskell中使用映射时跳过异常

在Haskell中使用映射时跳过异常,haskell,error-handling,map,Haskell,Error Handling,Map,我有以下代码以字符串形式返回一个周期的长度: 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 =

我有以下代码以字符串形式返回一个周期的长度:

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]]
modulemain其中
导入数据。列表
检测ys n | 2*n>(长度ys)=错误“无周期”
|t==h=(2*n-n)
|否则=检测(n+1)
哪里
t=ys!!N
h=如果n==0,则ys!!1.其他人是谁!!(n*2)
f x=检测(显示x)0
answer=mapf[1/x | x您可以从控件中使用

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 (请注意,这也修复了第一个保护中允许
!!
抛出异常的错误。)

这允许类似但更灵活的使用,例如:

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
如果您根本不关心错误消息,那么就不要生成它们。一种自然的方法是使用列表,在列表中,您返回空列表,不循环,并使用
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]

最后,您可能对阅读感兴趣。

请不要使用
error
来实现预期会出现“错误”结果的逻辑

相反,为什么不返回
Maybe n
而不是只返回
n
,然后过滤掉
Nothing
s

这些变化非常简单:

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]]
modulemain其中
导入数据。列表
导入数据,也许吧
检测ys n | 2*n>(长度ys)=无
|t==h=Just(2*n-n)
|否则=检测(n+1)
哪里
t=ys!!n
h=如果n==0,则ys!!1否则ys!!(n*2)
f x=检测(显示x)0
你在做什么

仅仅因为某个数字重复,并不意味着你已经找到了一个循环:例如,在334/999=0.334…,这个循环不是(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

这假设它永远不会从列表的末尾跑出来。如果您实现自己的十进制扩展,您可以很容易地确保这是真的。

+1用于阻止
错误。
。请注意,甚至不可能对照它返回的
\u124;
进行检查!如果有经过计算的错误,整个程序将返回未定义。+1对于相同的错误,一个这也不利于数组索引,不过如果你一开始就指出OP的算法是错误的,我会更喜欢它。因为你没有,所以我做了…
catMaybes.map==mappaye
实际上,你可以捕捉到“错误”(和模式匹配失败)在IO中。但你永远都不想达到这一点;这不是一个例外,这是一个bug。要澄清两种方法之间的区别,请注意,
可能
也是一个monad。
MonadError
是一种更通用的方法,它允许你附加错误消息;如果你不关心错误消息,就没有太多的实践cal差异,两者都可以“直接”样式或使用
do
表示法编写。
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]]
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