默认情况下,如果一个函数的方程没有匹配给定的参数,你会得到一个运行时错误:
fromJust :: Maybe a -> a
fromJust (Just a) = a
-- No case for Nothing
-- fromJust Nothing throws error at runtime
但是,这不适用于数字。相反,守卫会做类似的事情:
assertOver0 :: Int -> ()
assertOver0 n | n > 0 = ()
-- No case for n <= 0
-- assertOver0 (-1) throws error at runtime
虽然这是默认行为,但模式/防护不完整是不好的风格。相反,使用error 或undefined 显式导致错误:
pr n | n >= 0 = filter (null . getter) [2..] !! n
| otherwise = error "Table flip"
-- undefined is just like error, except that error lets you give an error message
-- and undefined doesn't (undefined is more useful when you know it will never
-- be evaluated, and you don't need to give an error message)
-- undefined :: a; error :: String -> a
-- That is, they can take on any type you want them to have, because whatever code
-- is after them will never be executed anyway
-- I took liberties with your definition of pr. Your filtering function didn't use
-- x, so I wrote what I think you meant. I also made it 0-indexed.
-- Prelude.null checks for [], but doesn't incur an Eq constraint, so I replaced
-- (== []) with it.
-- Parens are not needed around the filter, because function application has
-- the highest precedence.
Haskell 在Control.Exception 中也有一个更复杂的异常机制,但在这里你可能不需要它。一般来说,异常和部分函数是被看不起的,(因为你只能在IO中处理它们),你应该争取像Maybe或Either这样的monad。
import Control.Monad
pr n = do guard $ n >= 0 -- guard True = Just (); guard False = Nothing (in this case)
return $ filter (null . getter) [2..] !! n
pr 2 = Just 5
pr (-1) = Nothing
不过,所有这些都是不必要的。 (!!) 已经在负索引上出错了
ghci> "abc" !! -1
*** Exception: Prelude.!!: negative index
所以我们又回到了开始的地方:
pr n = filter (null . getter) [2..] !! n
还有a library 将列表操作(包括(!!))重新定义为单子而不是部分。