Haskell等同于assert(0)

时间:2019-02-11 05:26:32

标签: haskell assert

我正在尝试找出写与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

2 个答案:

答案 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的类型,任何调用者都知道他们必须处理JustNothing两种情况,而不必诉诸于相关函数的代码或文档