Haskell 相当于 assert(0)
Haskell equivalent of assert(0)
我正在尝试找出编写 Haskell 等同于 assert(0)
的最佳实践。我知道类型安全规定必须从 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
来自 assert
的文档:
If the first argument evaluates to True, then the result is the second argument. Otherwise an AssertionFailed exception is raised, containing a String with the source file and line number of the call to assert.
因此,与其将 False
作为第一个参数,您实际上可以在那里检查您的 if
条件:
scanList (x:xs) = case x of
Right i -> i + scanList xs
Left s ->
assert (read s < 8) (read s + scanList xs)
更惯用的 Haskell 设计是保持纯函数 总数 。使用 assert
时,您将抛出异常,这使得函数 partial。这意味着您不能再信任函数的类型。它声称具有 [Either String Int] -> Int
类型,但在各种条件下会在 运行 时间出现异常而失败。
总函数要么保留在 Either
monad 中,要么可以转换为 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
两种情况,而不必求助于阅读函数的代码或文档有问题。
我正在尝试找出编写 Haskell 等同于 assert(0)
的最佳实践。我知道类型安全规定必须从 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
来自 assert
的文档:
If the first argument evaluates to True, then the result is the second argument. Otherwise an AssertionFailed exception is raised, containing a String with the source file and line number of the call to assert.
因此,与其将 False
作为第一个参数,您实际上可以在那里检查您的 if
条件:
scanList (x:xs) = case x of
Right i -> i + scanList xs
Left s ->
assert (read s < 8) (read s + scanList xs)
更惯用的 Haskell 设计是保持纯函数 总数 。使用 assert
时,您将抛出异常,这使得函数 partial。这意味着您不能再信任函数的类型。它声称具有 [Either String Int] -> Int
类型,但在各种条件下会在 运行 时间出现异常而失败。
总函数要么保留在 Either
monad 中,要么可以转换为 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
两种情况,而不必求助于阅读函数的代码或文档有问题。