2016-01-16 54 views
3

說我有一個功能:測試函數返回一個單子可能

safeHead :: [a] -> Maybe a 
safeHead [] = Nothing 
safeHead xs = Just $ head xs 

和測試:

describe "Example.safeHead" $ do 
    it "returns the head" $ do 
    safeHead [1,2,3] `shouldBe` Just 1 

    it "returns Nothing for an empty list" $ 
    safeHead [] `shouldBe` Nothing 

然而,這會產生:

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 forall (k :: BOX) (s :: k). Eq (Data.Proxy.Proxy s) 
    -- Defined in ‘Data.Proxy’ 
    instance (GHC.Arr.Ix i, Eq e) => Eq (GHC.Arr.Array i e) 
    -- Defined in ‘GHC.Arr’ 
    ...plus 88 others 
In the second argument of ‘($)’, namely 
    ‘safeHead [] `shouldBe` Nothing’ 
In a stmt of a 'do' block: 
    it "returns Nothing for an empty list" 
    $ safeHead [] `shouldBe` Nothing 
In the second argument of ‘($)’, namely 
    ‘do { it "returns the head" 
     $ do { safeHead [...] `shouldBe` Just 1 }; 
     it "returns Nothing for an empty list" 
     $ safeHead [] `shouldBe` Nothing }’ 

爲什麼?我該如何解決它?

+0

safeHead [] \ shouldBe \'Nothing'的類型是不明確的,因爲沒有任何東西可以告訴編譯器列表元素的比較中使用哪種元素類型(當然,這不重要,因爲那裏沒有元素,但編譯器不知道)。你可以通過給定一個明確的類型來解決它:'safeHead [] \'shouldBe''(Nothing :: Maybe Int)'。 – user2407038

回答

2
shouldBe    :: (Eq a, Show a) => a -> a -> Expectation 
safeHead    ::   [a] -> Maybe a 
[]      ::   [a] 
safeHead []    ::     Maybe a 
Nothing     ::     Maybe a 
shouldBe (safeHead []) :: (Eq a, Show a) => Maybe a -> Expectation 

shouldBe (safeHead []) Nothing ::      Expectation -- but what's `a`? 

正如你所看到的,a完全是不明確的。它可以是具有ShowEq實例的任何類型。這也是你的錯誤消息的一部分:

 
No instance for (Eq a0) arising from a use of ‘shouldBe’ 
The type variable ‘a0’ is ambiguous 

所以挑一個:

it "returns Nothing for an empty list" $ 
    safeHead [] `shouldBe` (Nothing :: Maybe()) 

當你在它,使用快速檢查驗證safeHead作品像head

it "returns Just (head xs) for a non-empty list" $ property $ \(NonEmpty xs) -> 
    safeHead xs `shouldBe` (Just (head xs) :: Maybe Integer) 
4

正如user2407038所評論的,編譯器不知道如何實例化a。他提出的修正可能是最好的 - 你應該明確指定類型a

但對於完整性,我想指出,有其他的解決方案,extended default rules

{-# LANGUAGE ExtendedDefaultRules #-} 

describe "Example.safeHead" $ do 
    it "returns the head" $ do 
    safeHead [1,2,3] `shouldBe` Just 1 

    it "returns Nothing for an empty list" $ 
    safeHead [] `shouldBe` Nothing 

擴展修改the standard defaulting rules,包括更多的情況下,例如Eq類型的類。

加入:經過一番思考,我重新考慮了一下我的答案。多態函數的單元測試結果不應該依賴於特定方式來實例化類型變量。所以可能擴展的默認規則是測試中的正確事物?我從來沒有用過它真正的代碼,所以我不能肯定地說,但它絕對值得考慮。

+0

很有意思。我很想知道該解決方案在給出類型規範方面的相對優缺點?或者它的字面意思是「優點:少打字,缺點:寬鬆類型」? –

+0

@AbrahamP基本上可以,少打字可能是唯一的優點:) – Yuras

相關問題