我正在尝试找出写与assert(0)
等效的Haskell的最佳实践。我知道类型安全性指示必须从scanList
返回一个整数,但是我想知道是否有比我写的更好的方法。有什么方法可以避免卡在其中的任意数字923
?
module Main (main) where
import Control.Exception (assert)
l = [
Left "1",
Left "1",
Right 1,
Right 1,
Left "9"]
scanList :: [ Either String Int ] -> Int
scanList [ ] = 0
scanList (x:xs) = case x of
Right i -> i + scanList xs
Left s ->
if read s < 8
then read s + scanList xs
else assert False $ 923
main = do
print $ scanList l
答案 0 :(得分:7)
摘自assert
的文档:
如果第一个参数的计算结果为True,则结果为第二个参数。否则,将引发AssertionFailed异常,其中包含一个String,其中包含要断言的源文件和调用的行号。
因此,您不必实际在此处检查False
的条件,而不必将if
作为第一个参数:
scanList (x:xs) = case x of
Right i -> i + scanList xs
Left s ->
assert (read s < 8) (read s + scanList xs)
答案 1 :(得分:5)
Haskell更加惯用的设计是将纯功能总计保留。使用assert
时,您将引发异常,从而使函数 partial 。这意味着您不再可以相信函数的类型。它声称具有类型[Either String Int] -> Int
,但在各种情况下都会在运行时失败,并出现异常。
全部功能要么停留在Either
单子之内,要么可以转换为Maybe
:
import Text.Read
scanList :: (Num a, Read a, Ord a) => [Either String a] -> Maybe a
scanList [] = Just 0
scanList (x:xs) =
case x of
Right i -> fmap (+ i) $ scanList xs
Left s ->
case readMaybe s of
Just i -> if i < 8 then fmap (+ i) $ scanList xs else Nothing
Nothing -> Nothing
您可以简化代码,但我选择使其在结构上尽可能接近OP。
使用类似[Either String a] -> Maybe a
的类型,任何调用者都知道他们必须处理Just
和Nothing
两种情况,而不必诉诸于相关函数的代码或文档