断言的Haskell等价物(0)

断言的Haskell等价物(0),haskell,assert,Haskell,Assert,我试图找出编写Haskell等价于assert(0)的最佳实践是什么。我知道类型安全性要求必须从扫描列表返回一个整数,但是我想知道是否有比我写的更好的方法。有没有办法避免卡在那里的任意数字923 module Main (main) where import Control.Exception (assert) l = [ Left "1", Left "1", Right 1, Right 1, Left "9"] scanList :: [ Ei

我试图找出编写Haskell等价于
assert(0)
的最佳实践是什么。我知道类型安全性要求必须从
扫描列表
返回一个整数,但是我想知道是否有比我写的更好的方法。有没有办法避免卡在那里的任意数字
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
主模块(Main),其中
导入控制。异常(断言)
l=[
左“1”,
左“1”,
对一,,
对一,,
左“9”]
扫描列表::[任意字符串Int]->Int
扫描列表[]=0
扫描列表(x:xs)=案例x
右i->i+扫描列表xs
左s->
如果读取s<8
然后读取s+scanlistxs
否则断言为假$923
main=do
打印$scanList

来自
断言
的文档:

如果第一个参数的计算结果为True,则结果为第二个参数。否则将引发AssertionFailed异常,该异常包含一个字符串,其中包含源文件和assert调用的行号

因此,您不必将
False
作为第一个参数,而是可以检查
是否存在以下条件:

scanList (x:xs) = case x of
    Right i -> i + scanList xs
    Left  s ->
        assert (read s < 8) (read s + scanList xs)
scanList(x:xs)=的情况x
右i->i+扫描列表xs
左s->
断言(读取s<8)(读取s+scanList xs)

更惯用的Haskell设计是保持纯函数的总量。当使用
assert
时,您抛出了一个异常,这使得函数部分。这意味着您不能再信任函数的类型。它声称其类型为
[orther String Int]->Int
,但在各种条件下运行时会出现异常而失败

一个total函数要么留在
单子中,要么可以转换为
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
导入文本。读取
扫描列表::(Num a,Read a,Ord a)=>[任一字符串a]->可能是a
扫描列表[]=仅为0
扫描列表(x:xs)=
案例十
右i->fmap(+i)$scanList xs
左s->
案例阅读
只需i->如果i<8,则fmap(+i)$scanList xs没有其他内容
无->无
您可以将代码简化很多,但我选择在结构上尽可能地使其接近OP


对于像
[字符串a]->可能是a
这样的类型,任何调用方都知道他们必须处理
只是
什么都不
的情况,而不必阅读相关函数的代码或文档。

我明白了。那么,在Haskell中是否有合理的场景可以使用断言呢?就像你说的,给定任何返回类型
T
的函数,我总是可以
Maybe
it并完全避免断言,对吗?为什么Haskell的人会启用它?@Orenishalom有几个原因说明异常仍然是Haskell的一部分。其中之一是Haskell是一种古老的语言,由于历史或向后兼容的原因,某些语言特征仍然存在。另一个原因是,您可能认为异常在
IO
的上下文中仍然是合适的,因为函数已经不纯了。@orenishhalom,断言用于检查代码是否正确。在许多情况下,您确实可以通过仔细确保不变量在结构上或通过类型系统强制执行来避免它们。但有时你不能,或者不容易做到。假设你有一棵重量平衡的树。您可以将断言添加到重新平衡操作中,以验证每个生成的节点是否真正得到了适当的平衡。我建议仅对代码中的不变量使用断言(如果失败意味着错误),它们有助于记录不变量并补充您的测试<代码>断言
调用没有开销,因为它们在使用优化编译时被删除