3

A while ago I've asked a question about the function elem here, but I don't think the answer is fully satisfactory. My question is about the expression:

any (`elem` [1, 2]) [1, 2, 3]

We know elem is in a backtick so elem is an infix and my explanation is:

1 `elem` [1, 2] -- True
2 `elem` [1, 2] -- True
3 `elem` [1, 2] -- False

Finally it will return True since it's any rather than all. This looked good until I see a similar expression for isInfixOf:

any (isInfixOf [1, 2, 3]) [[1, 2, 3, 4], [1, 2]]

In this case a plausible explanation seems to be:

isInfixOf [1, 2, 3] [1, 2, 3, 4] -- True
isInfixOf [1, 2, 3] [1, 2]       -- False

I wonder why they've been used in such different ways since

any (elem [1, 2]) [1, 2, 3]

will give an error and so will

any (`isInfixOf` [[1, 2, 3, 4], [1, 2]]) [1, 2, 3]
Community
  • 1
  • 1
manuzhang
  • 2,995
  • 4
  • 36
  • 67

3 Answers3

8

Your problem is with the (** a) syntactic sugar. The thing is that (elem b) is just the partial application of elem, that is:

(elem b) == (\xs -> elem b xs)

However when we use back ticks to make elem infix, we get a special syntax for infix operators which works like this:

(+ a) == (\ b -> b + a)
(a +) == (\ b -> a + b)

So therefore,

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

while

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

So in the latter case your arguments are in the wrong order, and that is what is happening in your code.

Note that the (** a) syntactic sugar works for all infix operators except - since it is also a prefix operator. This exception from the rule is discussed here and here.

Community
  • 1
  • 1
HaskellElephant
  • 9,819
  • 4
  • 38
  • 67
  • So how about the case of **isInfixOf**? – manuzhang Oct 21 '11 at 12:52
  • @manuzhang, the arguments also get in the opposite order for `isInfixOf`, just apply the same reasoning as in the answer. I thought about editing in that case but it is just copy paste what I said with `elem` replaced with `isInfixOf`. – HaskellElephant Oct 21 '11 at 12:57
  • @HaskellElepant Thx I've got it. The opposite ways could be `any (elem [1,2,3])[[[1,2,3],[1,2,4]],[[1,2,5]]]` and `any (\`isInfixOf\` [1,2,3,4]) [[1,2,3],[1,2,3,4,5]]` – manuzhang Oct 21 '11 at 13:22
  • If my answer helped, feel free to upvote or even accept the answer. – HaskellElephant Oct 21 '11 at 13:24
  • Of course and that's what I've done! I'm new to Haskell, have no knowledge of lambda function and still getting accustomed to functional programming. Really appreciate your help. – manuzhang Oct 21 '11 at 22:35
3

Using back-ticks around a function name turns it into an infix operator. So

x `fun` y

is the same as

fun x y

Haskell also has operator sections, f.e. (+ 1) means \x -> x + 1.

So

(`elem` xs)

is the same as

\x -> x `elem` xs

or

\x -> elem x xs

or

flip elem xs
Sjoerd Visscher
  • 11,840
  • 2
  • 47
  • 59
0

It's called partial application.

isInfixOf [1, 2, 3] returns a function that expects one parameter.

any (elem [1, 2]) [1, 2, 3] is an error because you're looking for an element [1, 2], and the list only contains numbers, so haskell cannot match the types.

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • 1
    But `any (elem [1, 2]) [[1,2],[1,2,3]]` won't do either – manuzhang Oct 21 '11 at 12:37
  • `elem [1, 2] [[1,2],[1,2,3]]` should typecheck, but as you say, `any (elem [1, 2]) [[1,2],[1,2,3]]` does not. I think what you want here is `any (elem [1, 2]) [[[1,2,3],[1,2,4]],[[1,2,5]]]` as you said in another comment. So you have a list of lists of lists. – Tyler Oct 21 '11 at 19:32