#haskell #quickcheck #hspec
#хаскелл #быстрая проверка #hspec
Вопрос:
Я борюсь с семантикой where
внутри do
блоков, в частности с 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 -gt; f x `shouldBe` (x :: Int) describe "bar" $ do it "id" $ property $ x -gt; x `shouldBe` (x :: Int)
Это не означает:
module ExampleSpec where import Test.Hspec import Test.QuickCheck spec :: Spec spec = do describe "foo" $ do it "id" $ property $ x -gt; f x `shouldBe` (x :: Int) where f = id describe "bar" $ do it "id" $ property $ x -gt; x `shouldBe` (x :: Int)
Это не удается с:
/mnt/c/haskell/chapter15/tests/ExampleSpec.hs:13:5: error: parse error on input ‘describe’ | 13 | describe "bar" $ do | ^^^^^^^^
Я делаю что-то не так или это какое-то врожденное ограничение where
?
Комментарии:
1. Я должен добавить, что я пытался поиграть с
{}
этим, но;
безрезультатно2. Мне нравится, как ты используешь
where
это выражение. Многие из нас думаютwhere
, что это должно быть выражение и его можно использовать так же, как вы сделали это выше. Однако, как объясняют приведенные ниже ответы,where
он более ограничен и может появляться только в определенных местах (например, как часть декларации).
Ответ №1:
where
Предложение может быть прикреплено только к функции или привязке к регистру и должно располагаться после текста с правой стороны.
Когда компилятор видит where
, он знает, что RHS вашего spec = ...
уравнения закончен. Затем он использует отступ, чтобы выяснить, насколько далеко простирается блок определений внутри where
( f = id
в данном случае только один). После этого компилятор ищет начало следующего определения области модуля, но отступ describe "bar" $ do
недопустим для начала определения, что является ошибкой, которую вы получаете.
Вы не можете случайным образом вставить where
предложение в середину определения функции. Его можно использовать только для добавления вспомогательных привязок в область действия по всему RHS привязки; его нельзя использовать для добавления локальных привязок в область действия для произвольного под-выражения.
Однако существует именно let ... in ...
для этой цели. И поскольку вы используете do
блоки под каждым describe
из них , вы также можете использовать let
оператор (используя оставшуюся часть do
блока для ограничения области локальных привязок вместо in
части let ... in ...
выражения). Так что вы можете сделать это вместо этого:
spec = do describe "foo" $ do let f = id it "id" $ property $ x -gt; f x `shouldBe` (x :: Int) describe "bar" $ do it "id" $ property $ x -gt; x `shouldBe` (x :: Int)
Комментарии:
1. Я заметил, что без
in
затенения назначений происходит использование на одном и том же уровне отступов. Имеет смысл, просто примечание2. @BenHeilman Это синтаксическая проблема и на самом деле не связана с семантикой. Семантика описывает значение синтаксически допустимого кода, а код в вопросе не является синтаксически допустимым.
3.@BenHeilman Я не на 100% уверен, что вы имеете в виду под этим. Привязки, введенные в
let
инструкции (в блоке do, безin
ключевого слова), охватывают всю остальную часть блока do, в котором они встречаются (поэтому все, что следует за этим, является частью конструкции, начинающейся с того же отступа, да). Привязки, введенныеlet ... in ...
выражением, распространяются на выражение вin ...
детали (ноlet ... in ...
выражения используют отступ только для блока привязок, а неin ...
для детали). Любой из них будет скрывать привязки из охватывающих областей, как и любой метод привязки имени.
Ответ №2:
Это синтаксическое ограничение в соответствии с правилами области действия блока where. Внутри where
блока значения, связанные в соответствии с шаблоном, находятся в области действия, а значения, определенные в where
блоке, находятся в области действия для охранников в пределах этого соответствия шаблону. Таким образом, where
блок должен быть прикреплен к местам, где по крайней мере может существовать соответствие шаблону и охранники. Это заканчивается объявлениями значений и ветвями выражений регистра. Во втором примере вы пытаетесь прикрепить where
блок к произвольному выражению, что просто не то, для чего они предназначены.