为什么我不能去Hspec的"哪里"工作



我很难理解do块中where的语义,尤其是Test.Hspec。以下工作:

module ExampleSpec where
import Test.Hspec
import Test.QuickCheck
spec :: Spec
spec = do
describe "foo" $ do
let
f = id
in
it "id" $ property $
x -> f x `shouldBe` (x :: Int)
describe "bar" $ do
it "id" $ property $
x -> x `shouldBe` (x :: Int)

这不是:

module ExampleSpec where
import Test.Hspec
import Test.QuickCheck
spec :: Spec
spec = do
describe "foo" $ do
it "id" $ property $
x -> f x `shouldBe` (x :: Int)
where
f = id
describe "bar" $ do
it "id" $ property $
x -> x `shouldBe` (x :: Int)

它失败了:

/mnt/c/haskell/chapter15/tests/ExampleSpec.hs:13:5: error: parse error on input ‘describe’
|
13 |     describe "bar" $ do
|     ^^^^^^^^

我是做错了什么,还是where有某种固有的局限性?

where子句只能附加到函数或大小写绑定,并且必须位于右侧正文之后。

当编译器看到where时,它知道spec = ...方程的RHS已经结束。然后,它使用缩进来计算where内部的定义块延伸了多远(在这种情况下,只有单个f = id(。接下来,编译器将寻找下一个模块范围定义的开始,但缩进的describe "bar" $ do对于定义的开始无效,这就是您得到的错误。

不能在函数定义的中间随机插入where子句。只有可以用于在绑定的整个RHS范围内添加辅助绑定;它不能用于在任意子表达式的作用域中添加本地绑定。

然而,let ... in ...正是为了这个目的。由于在每个describe下使用do块,因此也可以使用let语句(使用do块的剩余部分来界定本地绑定的范围,而不是let ... in ...表达式的in部分(。所以你可以这样做:

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块中定义的值在该模式匹配中的保护范围内。因此,where块必须连接到模式匹配的位置,并且至少可以存在保护。这最终成为值声明和大小写表达式的分支。在第二个例子中,您试图将where块附加到任意表达式上,这不是它们想要做的

相关内容

  • 没有找到相关文章

最新更新