这是对我最后一个问题的扩展:基本的haskell:复制元素
但是,当添加无效输入时,我希望它打印出一条错误消息,说“负值”或类似的东西。这在haskell中可能吗?工作代码:
copy :: Int->a->[a]
copy 0 _ = []
copy y a = [a]++(copy (y-1) a)
最后一行:
copy b c = error "negative value"
这是对我最后一个问题的扩展:基本的haskell:复制元素
但是,当添加无效输入时,我希望它打印出一条错误消息,说“负值”或类似的东西。这在haskell中可能吗?工作代码:
copy :: Int->a->[a]
copy 0 _ = []
copy y a = [a]++(copy (y-1) a)
最后一行:
copy b c = error "negative value"
因为偏函数让我难过,我建议做更多的事情
copy :: Int -> a -> Maybe [a]
copy 0 _ = Just []
copy n a | n < 0 = Nothing
| otherwise = fmap (a:) (copy (n-1) a)
我们已经把它换成了if
“守卫”
foo bar | baz = quux
| ...
只是
foo bar = if baz then quux else ...
请注意,我还稍微更改了您的代码,
[a] ++ copy (y-1) a ====> fmap (a:) (copy (y-1) a)
你可以认为(:)
是追加。
1 : [2, 3] ==> [1, 2, 3]
它是[1] ++ [2, 3]
. 大声说出“缺点”,例如“构造”。我们可以用操作符部分来写这个
(a:) ==> \x -> a : x
接下来我们使用这个不稳定fmap
的功能。fmap
这样想
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
所以它Just
在重新包装结果之前打开 a 并应用一个函数。因此,如果我们的数字为负数,我们的最终代码将返回Nothing
,否则,仅返回列表。
为什么我不推荐error
?好吧,因为error
会用非常少的信息来炸毁你的整个程序,尝试抓住它是个坏主意。Haskell 甚至没有强制要求这样做,GHC 只是error
以一种可能的方式实现。换句话说,你几乎没有机会恢复。
对于 10 行代码来说,这没什么大不了的,但我已经花费了 6 个小时以上的时间来寻找对使用error
. 调试和更惯用的haskell要快得多。
你可以用守卫做到这一点
copy :: Int -> a -> [a]
copy n x
| n < 0 = error "negative value"
| n == 0 = []
| otherwise = x : copy (n - 1) x
但是,如果这失败了,那么它可能会使您的程序崩溃。更好的方法是使用Maybe
类型:
copySafe :: Int -> a -> Maybe [a]
copySafe n x
| n < 0 = Nothing
| otherwise = Just (copy n x)
然后您可以将其用作
main = do
putStrLn "Enter a number:"
nStr <- getLine
let n = read nStr :: Int
maybeXs = copySafe n n
case maybeXs of
Nothing -> putStrLn "You entered a negative number!"
Just xs -> print xs
这种风格迫使你考虑两种情况copySafe
,要么它可能因负值而失败,要么它可以返回一个有效列表。它不会使您的程序崩溃,并且错误处理由类型系统强制执行。
看看http://www.haskell.org/haskellwiki/Error_vs._Exception
例如
copy b c = if c > b then error "negativ value"