HSpec Ничего не ожидание не удалось скомпилировать

Я изучаю Haskell и написал эту функцию:

safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:xs) = Just x

Сейчас я пытаюсь проверить это с помощью HSpec:

import Test.Hspec

main :: IO ()
main = hspec spec

spec :: Spec
spec =

  describe "safeHead" $
    it "should return Nothing for empty list" $
      safeHead [] `shouldBe` Nothing

Но это не скомпилируется:

Error:(14, 19) ghc: No instance for (Eq a0) arising from a use of ‘shouldBe’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Eq a => Eq (Maybe a) -- Defined in ‘GHC.Base’
      instance Eq a => Eq (GHC.Real.Ratio a) -- Defined in ‘GHC.Real’
      instance Eq Ordering -- Defined in ‘ghc-prim-0.4.0.0:GHC.Classes’
      ...plus 31 others
    In the second argument of ‘($)’, namely
      ‘safeHead [] `shouldBe` Nothing’
    In the second argument of ‘($)’, namely
      ‘it "should return Nothing for empty list"
       $ safeHead [] `shouldBe` Nothing’
    In the expression:
      describe "safeHead"
      $ it "should return Nothing for empty list"
        $ safeHead [] `shouldBe` Nothing

Я также пробовал это:

safeHead :: (Eq a) => [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:xs) = Just x

Но это все еще не удается с:

Error:(14, 19) ghc: No instance for (Eq a0) arising from a use of ‘shouldBe’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance (Eq a, Eq b) => Eq (Either a b)
        -- Defined in ‘Data.Either’
      instance Eq Data.Monoid.All -- Defined in ‘Data.Monoid’
      instance forall (k :: BOX) (f :: k -> *) (a :: k).
               Eq (f a) =>
               Eq (Data.Monoid.Alt f a)
        -- Defined in ‘Data.Monoid’
      ...plus 43 others
    In the second argument of ‘($)’, namely
      ‘safeHead [] `shouldBe` Nothing’
    In the second argument of ‘($)’, namely
      ‘it "should return Nothing for empty list"
       $ safeHead [] `shouldBe` Nothing’
    In the expression:
      describe "safeHead"
      $ it "should return Nothing for empty list"
        $ safeHead [] `shouldBe` Nothing

Я не знаю, в чем здесь проблема. Если я попробую другие тесты, подобные этим, он отлично скомпилируется:

    it "should return the head" $ do
      safeHead [1] `shouldBe` Just 1
      safeHead [2,3,4,5,6,1] `shouldBe` Just 2

Значит, дело в самом Nothing, что его нельзя сравнивать на равных? Как вы тогда утверждаете, что что-то возвращает Nothing? Или моя функция слишком общая?

ПРИМЕЧАНИЕ. Я видел аналогичную ошибку с этой функцией:

palindrome :: (Eq a) => [a] -> [a]
palindrome xs = xs ++ reverse xs

При попытке проверить пустые списки:

palindrome [] `shouldBe` []

Что не удается с:

Error:(26, 21) ghc: No instance for (Eq a0) arising from a use of ‘shouldBe’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Eq a => Eq (Maybe a) -- Defined in ‘GHC.Base’
      instance Eq a => Eq (GHC.Real.Ratio a) -- Defined in ‘GHC.Real’
      instance Eq Ordering -- Defined in ‘ghc-prim-0.4.0.0:GHC.Classes’
      ...plus 32 others
    In a stmt of a 'do' block: palindrome [] `shouldBe` []
    In the second argument of ‘($)’, namely
      ‘do { palindrome [] `shouldBe` [] }’
    In the second argument of ‘($)’, namely
      ‘it
         "should turn a list into a palindrome, so it reads same both forwards and backwards"
       $ do { palindrome [] `shouldBe` [] }’

person Galder Zamarreño    schedule 03.06.2015    source источник
comment
попробуйте safeHead ([] :: [Int]) shouldBe` Ничего`   -  person Random Dev    schedule 03.06.2015
comment
Это сработало! В чем причина этого? Вы принуждаете параметр иметь тип? Как актерский состав?   -  person Galder Zamarreño    schedule 03.06.2015
comment
@Zeta дала действительно хороший ответ на этот вопрос   -  person Random Dev    schedule 03.06.2015


Ответы (1)


Значит, дело в самом Ничто, что его нельзя сравнивать на равных?

Какой тип у Nothing? Это Nothing :: Maybe a. И GHC не нравится a в этом контексте: «Переменная типа ‘a0’ неоднозначна». Ведь shouldBe берет все, что можно сравнить с (==) и показать. И Maybe a является экземпляром Eq, если a является экземпляром Eq. GHC не может знать, какой a вы хотите использовать, поэтому вам нужно указать его вручную:

  describe "safeHead" $
    it "should return Nothing for empty list" $
      safeHead [] `shouldBe` (Nothing :: Maybe Int)

Это не принуждение, вы просто четко указываете, какой из всех возможных типов вы хотите использовать. Другие примеры:

  describe "safeHead" $
    it "should return Nothing for empty list" $ do
      safeHead [] `shouldBe` (Nothing :: Maybe Int)
      safeHead [] `shouldBe` (Nothing :: Maybe ())
      safeHead [] `shouldBe` (Nothing :: Maybe Integer)
      safeHead [] `shouldBe` (Nothing :: Maybe Char)
person Community    schedule 03.06.2015
comment
Спасибо за подробное объяснение :) - person Galder Zamarreño; 03.06.2015