Haskell / HSpec:了解错误消息

时间:2014-07-25 10:24:38

标签: haskell

我有以下函数应该返回列表的最后一个元素:

myButLast :: [a] -> a
myButLast [] = error "List has less than one element!"
myButLast [x] = error "List has less than one element!"
myButLast [x,_] = x
myButLast (_:xs) = myButLast xs

当我将其加载到ghci时,它适用于所有特殊情况,但是当我尝试使用HSpec进行测试时,运行此规范时出现错误:

main :: IO ()
main = hspec $ do

  describe "myButLast" $ do

    -- removed other specs --

    it "throws an error when called with a singleton list" $
      myButLast [1] `shouldThrow` anyErrorCall

这是错误消息:

No instance for (Num (IO a0)) arising from the literal `1'
    Possible fix: add an instance declaration for (Num (IO a0))
    In the expression: 1
    In the first argument of `myButLast', namely `[1]'
    In the first argument of `shouldThrow', namely `myButLast [1]'

有趣的是,编译器在测试myButLast []而不是myButLast [1]时不会抱怨,尽管两个表达式的结果定义完全相同。

2 个答案:

答案 0 :(得分:1)

正如西蒙指出的那样:

myButLast [1]只有错误的类型,即Num a => a,而shouldThrow需要第一个类型为IO a的参数。

所以,更有趣的问题是:

为什么编译器没有抱怨myButLast []的类型?

原因是:由于文字[]也可以是[IO a]类型,编译器会将myButLast []的类型推断为IO a,因为这是唯一可能是shouldThrow的有效第一个参数。

答案 1 :(得分:0)

回答问题背后的问题:要编写测试,您要使用evaluate

import Control.Exception.Base

main :: IO ()
main = hspec $ do

  describe "myButLast" $ do

    it "throws an error when called with a singleton list" $
      evaluate (myButLast [1]) `shouldThrow` anyErrorCall