为什么Hspec的do代码块中where语法无法正常工作?
问题结论
这是Haskell中where关键字的固有语法限制,和Hspec测试框架无关,你的代码逻辑没有问题,只是不符合Haskell的语法规则。
语法规则说明
where子句的作用域是绑定到它前面紧邻的完整声明/表达式,不能嵌套在do代码块的中间使用。你给出的错误代码中,where被放在了describe "foo"对应的do块内部,相当于将整个describe "foo" $ do ... where f = id视作一个完整表达式,直接截断了spec对应的顶层do块,后续的describe "bar"语句不属于任何合法语法结构的一部分,因此触发解析错误。
两种局部绑定的差异
- 你第一份代码中使用的
let...in是表达式级别的局部绑定,作用域仅覆盖in之后的代码片段,执行完该片段后绑定就失效,不会影响外层do块的后续语句,因此可以正常编译。 - 在
do块内做局部绑定更推荐直接省略in的let写法,同do块内let之后的所有语句都可以访问绑定的变量,写法更简洁:
spec :: Spec spec = do describe "foo" $ do let f = id it "id" $ property $ \x -> f x `shouldBe` (x :: Int) describe "bar" $ do it "id" $ property $ \x -> x `shouldBe` (x :: Int)
where的正确用法示例
如果你确实要使用where做绑定,需要将where放在完整声明的末尾,比如要让整个spec都能访问f,可以这么写:
spec :: Spec spec = do describe "foo" $ do it "id" $ property $ \x -> f x `shouldBe` (x :: Int) describe "bar" $ do it "id" $ property $ \x -> x `shouldBe` (x :: Int) where f = id
内容的提问来源于stack exchange,提问作者Ben Heilman
相关产品推荐
相关产品推荐

