wide_eyed_pupil
wide_eyed_pupil

Reputation: 3443

What's wrong with my quickCheck type declaration?

I roll my own elem function called elem'

elem' :: (Eq a) => a -> [a] -> Bool
elem' n ys = foldl (\acc p -> if (p == n) then True else False) False ys

Seems to work but I want to quickCheck it in GHCi so I import Test.QuickCheck

verboseCheck (\a -> (\xs ->( (elem' a xs) == (elem a xs)) ) )

Without a type declaration on the test function it tests ok, but that's because it's only testing null inputs.

Something is wrong with my type declaration for the test function:

verboseCheck (\a->(\xs->((elem' a xs)==(elem a xs))) :: Int->[Int]->Bool)
verboseCheck (\a->(\xs->((elem' a xs)==(elem a xs))) :: Char->[Char]->Bool)

Error for first one:

• Couldn't match expected type ‘[Int] -> Bool’
                  with actual type ‘Bool’
    • Possible cause: ‘(==)’ is applied to too many arguments
      In the expression: ((elem' a xs) == (elem a xs))
      In the expression:
          (\ xs -> ((elem' a xs) == (elem a xs))) :: Int -> [Int] -> Bool
      In the first argument of ‘verboseCheck’, namely
        ‘(\ a
            -> (\ xs -> ((elem' a xs) == (elem a xs))) ::
                 Int -> [Int] -> Bool)’

<interactive>:258:39: error:
    • Couldn't match expected type ‘[()]’ with actual type ‘Int’
    • In the second argument of ‘elem'’, namely ‘xs’
      In the first argument of ‘(==)’, namely ‘(elem' a xs)’
      In the expression: ((elem' a xs) == (elem a xs))

<interactive>:258:54: error:
    • Couldn't match expected type ‘[()]’ with actual type ‘Int’
    • In the second argument of ‘elem’, namely ‘xs’
      In the second argument of ‘(==)’, namely ‘(elem a xs)’
      In the expression: ((elem' a xs) == (elem a xs))

Upvotes: 3

Views: 117

Answers (1)

Mark Seemann
Mark Seemann

Reputation: 233135

This happens because Haskell thinks that you're constraining the return type of the lambda expression \a->(\xs->((elem' a xs)==(elem a xs))). This may be easier to see if you format the expression a bit more idiomatically:

\a -> (\xs -> ((elem' a xs) == (elem a xs)))

To the interpreter/compiler, this looks like a lambda expression that returns another expression. All good.

However, when you attempt to annotate it with a type:

\a -> (\xs -> ((elem' a xs) == (elem a xs))) :: Int -> [Int] -> Bool

Haskell thinks that you're annotating the return type, i.e. the right-most part closest associated with the type annotation: (\xs -> ((elem' a xs) == (elem a xs))).

Surround the entire lambda expression with brackets before applying the type:

(\a -> (\xs -> ((elem' a xs) == (elem a xs)))) :: Int -> [Int] -> Bool

You can now verboseCheck that expression:

Prelude Test.QuickCheck> verboseCheck ((\a -> (\xs -> ((elem' a xs) == (elem a xs)))) :: Int -> [Int] -> Bool)
Passed:
0
[]

Passed:
0
[]

Passed:
0
[-2,0]

Failed:
1
[2,1,-1]

Passed:
0
[2,1,-1]

Passed:
1
[]

Failed:
1
[1,-1]

Passed:
0
[1,-1]

Passed:
1
[]

Passed:
1
[-1]

Passed:
1
[1]

Passed:
1
[0,-1]

Passed:
1
[1,1]

Failed:
1
[1,0]

Passed:
0
[1,0]

Passed:
1
[]

Passed:
1
[0]

Passed:
1
[1]

Passed:
1
[0,0]

*** Failed! Falsified (after 4 tests and 2 shrinks):
1
[1,0]

Most of the brackets, however, are redundant, which is probably what's causing the confusion. You can simplify the expressions to this:

verboseCheck ((\a xs -> elem' a xs == elem a xs) :: Int -> [Int] -> Bool)
verboseCheck ((\a xs -> elem' a xs == elem a xs) :: Char -> [Char] -> Bool)

Upvotes: 5

Related Questions