haskell - 在 Haskell 中加强严格性

标签 haskell exception strict

在 Haskell 中做一些 TTD 时,我最近开发了以下功能:

import Test.HUnit
import Data.Typeable
import Control.Exception

assertException :: (Show a) => TypeRep -> IO a -> Assertion
assertException errType fun = catch (fun >> assertFailure msg) handle
    where
    msg = show errType ++ " exception was not raised!"
    handle (SomeException e) [...]

该函数采用预期异常和 IO 操作的类型表示。问题是,大多数时候,由于懒惰,我没有抛出异常,尽管我应该抛出异常。通常,fun 的失败部分实际上从未在这里进行评估。

为了解决这个问题,我尝试将 (fun >> assertFailure msg) 替换为 (seq fun $assertFailure msg)。我还尝试启用 BangPatterns 扩展并在 fun 绑定(bind)之前添加一个 bang,但没有任何帮助。那么我怎样才能真正迫使 Haskell 严格评估 fun 呢?

最佳答案

你必须区分:

  • 计算IO a类型的值
  • 运行它所代表的操作,这可能会产生副作用并返回 a 类型的值,并且
  • 评估类型 a(或其部分)的结果。

这些总是按这个顺序发生,但不一定是全部。代码

foo1 :: IO a -> IO ()
foo1 f = do
   seq f (putStrLn "done")

只会做第一个,而

foo2 :: IO a -> IO ()
foo2 f = do
   f -- equivalent to _ <- f
   putStrLn "done"

也执行第二个和最后一个

foo3 :: IO a -> IO ()
foo3 f = do
   x <- f 
   seq x $ putStrLn "done"

也执行第三个(但在复杂数据类型(如列表)上使用seq的常见注意事项适用)。

尝试这些参数并观察 foo1foo2foo3 对它们的处理方式不同。

f1 = error "I am not a value"
f2 = fix id -- neither am I
f3 = do {putStrLn "Something is printed"; return 42}
f4 = do {putStrLn "Something is printed"; return (error "x has been evaluated")}
f5 = do {putStrLn "Something is printed"; return (Just (error "x has been deeply evaluated"))}

关于haskell - 在 Haskell 中加强严格性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26445240/

相关文章:

java - 由相同类型的非静态成员引起的 StackOverflowError

typescript - Phaser + TypeScript 严格模式

Javascript:除了 "use strict"之外,还有哪些 "use"指令?

haskell - 在Haskell的列表上使用head函数时出现解析错误

haskell - 如何将附加参数传递给 Control.Monad.Reader 实例

haskell - 我如何指示 cabal-install 或 stack 使用 hackage 包的本地版本?

haskell - 嵌套 do 语法

java - 是否可以创建一个等待整个 try block 执行的 catch block ?

c++ - 对 std::runtime_error 的 what() 函数的误解

powershell - PowerShell-如何以编程方式确定是否设置了StrictMode?