我想弄清楚写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
Run Code Online (Sandbox Code Playgroud)
来自以下文件assert:
如果第一个参数的计算结果为True,那么结果就是第二个参数.否则会引发AssertionFailed异常,其中包含一个String,其中包含源文件和assert调用的行号.
因此,False您可以在if那里检查您的状况,而不是作为第一个参数给出:
scanList (x:xs) = case x of
Right i -> i + scanList xs
Left s ->
assert (read s < 8) (read s + scanList xs)
Run Code Online (Sandbox Code Playgroud)
更惯用的Haskell设计是保持纯函数的总和.使用时assert,你会抛出异常,这会使函数变为局部.这意味着您无法再信任该函数的类型.它声称具有该类型[Either String Int] -> Int,但在运行时在各种条件下将失败并出现异常.
总函数要么保留在Eithermonad中,要么可以转换为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
Run Code Online (Sandbox Code Playgroud)
您可以简化代码,但我选择在结构上保持尽可能接近OP.
与类型一样[Either String a] -> Maybe a,任何调用者都知道,他们必须同时处理Just和Nothing情况,而不必诉诸阅读有关的功能的代码或文档.