Sam
Sam

Reputation: 23

func = elem [1..10] works in GHCi but doesn't compile

In GHCi running this command

func = elem [1..10]

Works just fine and gives me a partial function back. I'm curious as to why it works? When I try compiling this code it gives me an error. For example this does not work work with other functions. Map gives me an error in GHCi and when I compile it.

func = map [1..10]

Curious what is special about GHCi and the function elem.

I know that I can write it as:

func = (`elem` [1..10])

func = (`map` [1..10])

And it works, but why does the other way work for elem.

Upvotes: 2

Views: 131

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120751

elem [1..10] is a perfectly sensible term. Example:

Prelude> elem [1..10] [[0..9], [1..10]]
True
Prelude> elem [1..10] [[0..8], [1..7]]
False

Perhaps more commonly, this would be written

Prelude> [1..10] `elem` [[0..9], [1..10]]
True
Prelude> [1..10] `elem` [[0..8], [1..7]]
False

but that's just a different syntactic version of the same thing.

That means also it can be compiled, you just need to give it an appropriate signature (or have GHC infer one for you). For example,

f :: [[Int]] -> Bool
f = elem [1..10]

...it's the function that tells you whether a list of number-lists contains the list [1..10]. I.e. like in any other use of elem, it tells you whether some list contains an element. The fact that this element happens to be itself a list is irrelevant.

On the other hand map [1..10] is just wrong, because the first argument to map must be a function. And lists, while they can be list-elements, can never be functions.

It's quite a different story with the operator-sections (`elem`[1..10]) and (`map`[1..10]). In those examples, [1..10] is actually the second argument. The section leaves out the left/first argument. So in this case what we're talking about is like

Prelude> 3 `elem` [1..10]
True
Prelude> 19 `elem` [1..10]
False

...and that also works with

Prelude> negate `map` [1..10]
[-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]

though that would be more commonly written map negate [1..10] or negate<$>[1..10].


In a sense that's simultaneously pedantic and anarchic, lists can actually be functions: with the -XOverloadedLists extension, you could write a class-instance that would allow you to define functions using list-syntax. I don't see how that could possibly make any sense, but maybe it's good to be aware of this theoretical possibility. In particular, with that extension enabled, map [1..10] confusingly does compile, and you merely get a confusing error involving Could not deduce ... The type variable ‘a0’ is ambiguous gibberish elsewhere.

Upvotes: 4

Related Questions