我有以下函数应该返回列表的最后一个元素:
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]
时不会抱怨,尽管两个表达式的结果定义完全相同。
答案 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