简体   繁体   English

为什么我不能在 Hspec 中找到工作地点

[英]Why cannot I get `where` to work in Hspec

I'm struggling with the semantics of where within do blocks, specifically with Test.Hspec .我正在努力解决do块中where的语义,特别是Test.Hspec The following works:以下作品:

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)

This does not:这不会:

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)

It fails with:它失败了:

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

Am I doing something wrong or is this some kind of inherent limitation with where ?我做错了什么还是这是某种固有的限制where

This is a syntactic restriction in service of the scoping rules of a where block.这是为 where 块的范围规则服务的语法限制。 Within a where block, values bound in a pattern match are in scope, and values defined in the where block are in scope for guards within that pattern match.where块中,模式匹配中绑定的值位于 scope 中,而where块中定义的值位于 scope 中,用于该模式匹配中的保护。 As such, a where block must be attached to locations where a pattern match and guards at the very least could exist.因此,必须将where块附加到至少可能存在模式匹配和守卫的位置。 This ends up being value declarations and branches of case expressions.这最终成为值声明和 case 表达式的分支。 In your second example you are trying to attach a where block to an arbitrary expression, which is just not what they're intended to do.在您的第二个示例中,您试图将where块附加到任意表达式,这不是他们打算做的。

A where clause can only be attached to a function or case binding, and must come after the right hand side body. where子句只能附加到 function 或大小写绑定,并且必须位于右侧正文之后。

When the compiler sees where , it knows that the RHS of your spec =... equation is over.当编译器看到where时,它就知道你的spec =...等式的 RHS 已经结束。 Then it uses indentation to figure out how far the block of definitions inside the where extends (just the single f = id in this case).然后它使用缩进来确定where中的定义块扩展了多远(在这种情况下只是单个f = id )。 Following that the compiler is looking for the start of the next module-scope definition, but an indented describe "bar" $ do is not valid for the start of a definition, which is the error you get.之后编译器正在寻找下一个模块范围定义的开始,但是缩进的describe "bar" $ do对于定义的开始是无效的,这是您得到的错误。

You cannot randomly insert a where clause into the middle of a function definition.您不能将where子句随机插入 function 定义的中间。 It only can be used to add auxiliary bindings in scope over the whole RHS of a binding;只能用于在 scope 中在绑定的整个 RHS 上添加辅助绑定; it cannot be used to add local bindings in scope for an arbitrary sub-expression.它不能用于在 scope 中为任意子表达式添加本地绑定。

However there is let... in... for exactly that purpose.然而,正是为了这个目的, let... in... And since you're using do blocks under each describe , you can also use the let statement (using the remainder of the do block to delimit the scope of the local bindings, instead of the in part of the let... in... expression).而且由于您在每个describe下使用do块,您还可以使用let语句(使用do块的其余部分来分隔本地绑定的 scope,而不是in部分let... in...表达式)。 So you can do this instead:所以你可以这样做:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM