1

这是对我最后一个问题的扩展:基本的haskell:复制元素

但是,当添加无效输入时,我希望它打印出一条错误消息,说“负值”或类似的东西。这在haskell中可能吗?工作代码:

copy :: Int->a->[a]
copy 0 _ = [] 
copy y a = [a]++(copy (y-1) a)

最后一行:

copy b c  = error "negative value"
4

3 回答 3

6

因为偏函数让我难过,我建议做更多的事情

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要快得多。

于 2013-10-18T20:13:13.630 回答
1

你可以用守卫做到这一点

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,要么它可能因负值而失败,要么它可以返回一个有效列表。它不会使您的程序崩溃,并且错误处理由类型系统强制执行。

于 2013-10-18T20:12:58.090 回答
-6

看看http://www.haskell.org/haskellwiki/Error_vs._Exception

例如

copy b c = if c > b then error "negativ value"
于 2013-10-18T19:42:47.980 回答