2

As an exercise I'm trying to implement interesting parts of the prelude manually. Whenever I spot an opportunity to go point free I take it. However this has led me to a brick wall in the most unlikely place. Using this code:

myelem _ [] = False 
myelem x y  = if x == head y then True else myelem x (tail y)

I am trying to implement notElem. Here are my attempts:

-- First
mynotelem = not myelem

Understandably blows up due to the types not matching up. This is easily fixed:

-- Second
mynotelem x y = not (myelem x y)

However the explicit declaration of arguments x and y feels ugly and unnecessary, so I try to get it back into point free style.

-- Third
mynotelem = not $ myelem

Which fails with

 Couldn't match expected type `Bool'
         with actual type `a0 -> [a0] -> Bool'
 In the second argument of `($)', namely `myelem'
 In the expression: not $ myelem
 In an equation for `mynotelem': mynotelem = not $ myelem

Fair enough, the types still don't match up. But how do you fix it? Again you can jump straight to

-- Fourth
mynotelem x y = not $ myelem x y

Which works, but seems dangerously close to just going in circles. I discover it's possible to eliminate one of the arguments:

-- Fifth
mynotelem x = not . (myelem x)

But that pesky x still remains. How do I eliminate it?

TheIronKnuckle
  • 7,224
  • 4
  • 33
  • 56
  • 2
    ThelronKnuckle: If you haven't already, search SO questions for ones regarding the difference between `($)` and `(.)` - I think you will find these questions/answers helpful. – Thomas M. DuBuisson Dec 28 '11 at 02:36

1 Answers1

12

We can rewrite your code like this:

mynotelem x = not . (myelem x)
            = (not .) (myelem x)

Now recognize that this is just h x = f (g x) with f = (not .) and g = myelem, so we can write it point-free with another use of the (.) operator as h = f . g:

mynotelem = (not .) . myelem

Note how the pattern continues when composing with functions with more arguments:

> let f x y z = x+y+z
> (((sqrt .) .) . f) 1 2 3
2.449489742783178

Alternatively, you can also write it with this funny-looking composition of composition operators:

mynotelem = ((.).(.)) not myelem

For more arguments, the pattern continues like this:

> ((.).(.).(.)) sqrt f 1 2 3
2.449489742783178
hammar
  • 138,522
  • 17
  • 304
  • 385
  • 3
    Shameless plug, I uploaded the "composition" package to hackage to provide convenience functions for the boob operator and friends. – Dan Burton Dec 28 '11 at 08:42
  • 3
    The boob operator XD Will have to use that as an advantage when pimping haskell to my mates – TheIronKnuckle Feb 03 '12 at 00:08
  • Is it at all common to use the "boob operator" in actual code? What's the cleanest way to handle a situation such as this? Would it be better to just leave it with its points (`mynotelem x = not . elem x` or `mynotelem x y = not $ elem x y`)? – Brandon Pickering Jan 03 '13 at 08:45