3

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))
wide_eyed_pupil
  • 3,153
  • 7
  • 24
  • 35

1 Answers1

5

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)
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Ah! I cribbed the parens pattern from my lecturer's example of a different function test, adapting it worked for a single arg function but not for double arg functions. his example was like this: `((\n -> (\s ->((decipher n (cipher n s)) == s))) :: Int -> [Char] -> Bool)` which obviously fits your pattern after some reductions. I'm sometimes unsure about where I need parens and where I don't because I don't understand all the precedence order for lambdas and other operators. A relevant tutorial link would be a great help. – wide_eyed_pupil May 26 '21 at 08:44
  • 1
    @wide_eyed_pupil To be honest, I haven't bothered learning those. I usually just add or remove brackets until things work. Also, if you use *hlint* it'll tell you if you have redundant brackets. – Mark Seemann May 26 '21 at 10:49
  • 1
    If you enable `:set -XTypeApplications` (in ghci) or `{-# LANGUAGE TypeApplications #-}` in your source file: `verboseCheck (\a xs -> elem' @Int a xs == elem a xs)`. If you want to specify it for `elem` instead you need to write `elem @[] @Int` or `elem @_ @Int`. You can get rid of parentheses with `-XBlockArguments`. – Iceland_jack May 26 '21 at 16:25
  • 1
    It is also possible to annotate the arguments of the argument to `verboseCheck`: `\(a :: Int) xs -> ..` or `\a (xs :: [Int]) -> ..` – Iceland_jack May 26 '21 at 16:27
  • Thx @MarkSeemann `hlint` sounds like the go. My lecturer has something in his terminal such that it behaves like a text editor which underlines paren pairs when the cursor is next to them or inside a pair of them, very helpful, I think he's using vim or emacs, I'm just using stock-standard (stack) GHCi. I found some useful info on SO & elsewhere about fixity and left-associative and right-associative which cleared a lot of it up for me. eg https://stackoverflow.com/questions/25589257/what-does-left-to-right-associativity-mean – wide_eyed_pupil May 26 '21 at 16:38
  • Thanks @Iceland_jack, a bit confusing for me to read as a novice but good to know! – wide_eyed_pupil May 26 '21 at 16:40
  • 1
    Polymorphic functions (`elem`, `(==)`) have types as invisible arguments, the `@` syntax lets you pass them explicitly. When you write `head "ABC"` it takes the character type as an invisible argument: `head @Char "ABC"`. It is useful to know, but maybe confusing. – Iceland_jack May 26 '21 at 17:02