Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointfree Composition with Multiple Variables

I've started to wrap my head around it, and rather like using it for simple situations in which I can essentially pipe the values from one output to one input. A simple example of a pointfree composition I'm comfortable with would be:

let joinLines = foldr (++) "" . intersperse "\n"

While playing with GHCI today, I wanted to see if I could compose not and (==) to replicate (/=), but I wasn't really able to reason it out. (==) take two inputs, and not takes one. I thought that this might work:

let ne = not . (==)

With the assumption that the single Bool output of (==) would go to not, but it won't compile, citing the following error:

<interactive>:1:16:
    Couldn't match expected type `Bool' with actual type `a0 -> Bool'
    Expected type: a0 -> Bool
      Actual type: a0 -> a0 -> Bool
    In the second argument of `(.)', namely `(==)'
    In the expression: not . (==)

I wish I could say it meant much to me, but all I'm getting is that maybe the second argument that's passed to (==) is mucking things up for not? Can anybody help me understand a little better the logic behind this composition?

like image 416
KChaloux Avatar asked Sep 13 '12 15:09

KChaloux


3 Answers

If you start to remove one argument at the time, you get

ne x y = not (x == y)
       = (not . (x ==)) y
ne x   = not . (x ==)
       = not . ((==) x)
       = ((not .) . (==)) x
ne     = (not .) . (==)

basically, for every argument you need one (.), properly associated.

The type of (==) is Eq a => a -> a -> Bool. So if you write whatever . (==), and pass a value x to that, you get whatever ((==) x), but (==) x is a function a -> Bool (where a is the type of x, and an instance of Eq). So the whatever must accept arguments of function type.

like image 87
Daniel Fischer Avatar answered Nov 15 '22 13:11

Daniel Fischer


Another useful operator is (.:), which is a combinator for an initial function taking two arguments:

f . g  $ x
f .: g $ x y
like image 26
John Wiegley Avatar answered Nov 15 '22 14:11

John Wiegley


Explicit use of curry and uncurry can help switch between "multi-argument" and single-argument functions.

ne = curry (not . uncurry (==))

uncurry "fixes" (==) so that it takes a single argument (x,y) rather than separate x and y arguments. The resulting function can then be composed with not as expected. The composed function, then can be re-curried to accept separate arguments again.

like image 3
chepner Avatar answered Nov 15 '22 15:11

chepner