'How can I use a type annotation to specify a variable in Haskell?

I am running test cases for functions I created in Haskell. I created a function called zip3Lists. It takes in any type (polymorphic arguments) of three lists and returns list of 3-tuples where each 3-tuple consists of the elements from each list consecutively. For instance, zip3Lists [1, 2, 3][4, 5, 6][7, 8, 9] would produce [(1, 4, 7), (2, 5, 8), (3, 6, 9)].

When testing the function, in my spec file, I have the following code to test when the function is used with 3 empty lists.

I get this long error on ‘shouldBe’ even though it matches my function return value:

Ambiguous type variable ‘a0’ arising from a use of ‘shouldBe’
      prevents the constraint ‘(Show a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Show Ordering -- Defined in ‘GHC.Show’
        instance Show Integer -- Defined in ‘GHC.Show’
        instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
        ...plus 22 others
        ...plus 45 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the second argument of ‘($)’, namely
        ‘zip3Lists [] [] [] `shouldBe` []’
      In a stmt of a 'do' block:
        it "produces the list  []" $ zip3Lists [] [] [] `shouldBe` []
      In the second argument of ‘($)’, namely
        ‘do it "produces the list  []" $ zip3Lists [] [] [] `shouldBe` []
            it "produces the list  []"
              $ zip3Lists [1, 2, ....] ['a', 'b', ....] [] `shouldBe` []
            it "produces the list  []"
              $ zip3Lists [1, 2, ....] [] [4, 5, ....] `shouldBe` []
            it "produces the list  [(1, 'a', 4), (2, 'b', 5), (3, 'c', 6)]"
              $ zip3Lists [1, 2, ....] ['a', 'b', ....] [4, 5, ....]
                  `shouldBe` [(1, 'a', 4), (2, 'b', 5), ....]
            ....’
   |        
13 |       zip3Lists [] [] [] `shouldBe` []

Is there a way I can fix this?



Solution 1:[1]

You can for example specify that the list should be a list of 3-tuples of Ints with:

spec :: Spec
spec = do
  describe "zip3Lists" $ do
    it "produces the list  []" $
      zip3Lists [] [] [] `shouldBe` ([] :: [(Int, Int, Int)])

Or you can work with the TypeApplications extension [haskell.org]:

{-# LANGUAGE TypeApplications #-}

spec :: Spec
spec = do
  describe "zip3Lists" $ do
    it "produces the list  []" $
      zip3Lists @Int @Int @Int [] [] [] `shouldBe` []

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Willem Van Onsem