How does the flip function work? - haskell

Haskell newbie here. I was going through Learn you a haskell, and came across this definition of the flip function.
flip' :: (a -> b -> c) -> (b -> a -> c)
flip' f = g
where g x y = f y x
What I don't get is, where did x and y come from? I mean, the signature tells me that flip' is a function that takes a function (with two parameters), and returns a function (again, with two parameters).
If I'm understanding this right, when I write a function which goes like
foo :: (a -> b) -> a -> b
foo f x = f x -- applies the function f on x
But then, in this case I'm passing the parameter explicitly [ ie x ] and so I'm able to access it in the function body. So how come the flip' function can access the parameters x and y?

The Prelude, which is in the base package at hackage.haskell.org, is included with an implicit import in every Haskell file is where the flip function is found. On the right side you can click "source" and see the source code for flip.
flip :: (a -> b -> c) -> b -> a -> c
flip f x y = f y x
The where clause allows for local definitions, x=10 or y="bla". You can also define functions locally with the same syntax you would for the top level. add x y = x + y
In the below equivalent formulation I make the substitution g = f y x
flip :: (a -> b -> c) -> b -> a -> c
flip f x y = g
where
g = f y x
Right now g takes no parameters. But what if we defined g as g a b = f b a well then we would have:
flip :: (a -> b -> c) -> b -> a -> c
flip f x y = g x y
where
g a b = f b a
No we can do a little algebraic cancelation(if you think of it like algebra from math class you will be pretty safe). Focusing in on:
flip f x y = g x y
Cancel the y on each side for:
flip f x = g x
Now cancel the x:
flip f = g
and now to put it back in the full expression:
flip :: (a -> b -> c) -> b -> a -> c
flip f = g
where
g a b = f b a
As a last cosmetic step we can make the substitution a to x and b to y to recover the function down to argument names:
flip :: (a -> b -> c) -> b -> a -> c
flip f = g
where
g x y = f y x
As you can see this definition of flip is a little round about and what we start with in the prelude is simple and is the definition I prefer. Hope that helps explain how where works and how to do a little algebraic manipulation of Haskell code.

flip' doesn't access x and y. It receives an argument f, and evaluates to the expression g. No x or y in sight.
However, g is itself a function, defined with an auxiliary equation in the where clause of flip'.
You can read g x y = f y x exactly as if it were a top level equation like flip'. So g is a function of two arguments, x and y. It's g that has access to x and y, not flip'. Values for those arguments don't exist until g is applied, which is not until after flip' has returned the function g (if ever).
The thing that's special that about g being defined in the where clause of flip' is that it can have access to the arguments of flip', which is how g can be defined in terms of f.
So when flip' is invoked it receives a function f. For each particular invocation of flip', it constructs a new function g. g would receive two arguments, x and y, when it is called, but that hasn't happened yet. flip' then just returns g as its result.

One simple example to understand and illustrate, on your ghci do:
Prelude> sub x y = x - y
Prelude> sub 3 1
2
Prelude> flip sub 3 1
-2

Let's find the type of g.
We know flip type : (a -> b -> c) -> (b -> a -> c)
Therefore we can deduce f type : (a -> b -> c)
We have this definition for g
g x y = f y x
From the right-hand-side we deduce that y :: a and x :: b.
Hence g :: b -> a -> c
Note that the definition could be rewritten without the 'where' clause.
flip' f = g where g x y = f y x
-> flip' f a b = g a b where g a b = f b a
-> flip' f a b = f b a

Put simply, you can also define functions in a where block. So the variables x and y are just the formal parameters of g, and that's why you can access it in g x y = f y x: g x y defines formal parameters x and y, and f y x is the definition of what g does. Finally, that definition is returned from flip f = g.

Related

Understanding the flip function

I am learning higher-order functions from 'Learn You a Haskell for Great Good!' by Miran Lipovaca.
For the following function flip which takes a function and returns a function with the first two arguments flipped:
flip' :: (a -> b -> c) -> (b -> a -> c)
flip' f = g
where g x y = f y x
I don't exactly understand what f and g are. Are they two different functions? Similarly, in the where binding, what exactly does g x y = f y x mean?
In the syntax:
myFunction x = x + 2
things on the left hand side of the equal sign, x, are treated as "parameters". You can use them on the right hand sign of the equal sign to state what you want the result to be.
This syntax defines a function myFunction, with single parameter x.
So here we have:
flip' f = g
This defines a function flip', with single parameter f.
We have another definition, as well:
g x y = f y x
This defines a function g, with two parameters, x and y.
So when we say:
flip' f = g
where
g x y = f y x
We are saying that the result of flip f is the function g, where g is defined as g x y = f y x.
In case the short variable names are confusing you, here is the same function with some of the names swapped for clarity:
flippity flop = glop
where
glop x y = flop y x
See if you can understand what flippity does, and see if you can see how it is the same as flip', just with different internal parameter and helper function names.
Remember also in Haskell that we can always replace function calls by their body, for the most part. So we can rewrite that as:
flippity flop = glop
where
glop = \x y -> flop y x
-- replace glop with its definition
flippity flop = \x y -> flop y x
So we can see that flippity is a function that takes a function flop and returns a new function, \x y -> flop y x.
f is flip''s input (the function you want to flip), g is flip's output (the flipped function it will return).
The where clause is simply defining what g is; that is, defining a function that simply calls f with its arguments reversed.
You could avoid naming g at all by simply having flip' return a lambda:
flip' :: (a -> b -> c) -> (b -> a -> c)
flip' f = \x y -> f y x

Explain (.)(.) to me

Diving into Haskell, and while I am enjoying the language I'm finding the pointfree style completely illegible. I've come a across this function which only consists of these ASCII boobies as seen below.
f = (.)(.)
And while I understand its type signature and what it does, I can't for the life of me understand why it does it. So could someone please write out the de-pointfreed version of it for me, and maybe step by step work back to the pointfree version sorta like this:
f g x y = (g x) + y
f g x = (+) (g x)
f g = (+) . g
f = (.) (+)
Generally (?) (where ? stands for an arbitrary infix operator) is the same as \x y -> x ? y. So we can rewrite f as:
f = (\a b -> a . b) (\c d -> c . d)
Now if we apply the argument to the function, we get:
f = (\b -> (\c d -> c . d) . b)
Now b is just an argument to f, so we can rewrite this as:
f b = (\c d -> c . d) . b
The definition of . is f . g = \x -> f (g x). If replace the outer . with its definition, we get:
f b = \x -> (\c d -> c . d) (b x)
Again we can turn x into a regular parameter:
f b x = (\c d -> c . d) (b x)
Now let's replace the other .:
f b x = (\c d y -> c (d y)) (b x)
Now let's apply the argument:
f b x = \d y -> (b x) (d y)
Now let's move the parameters again:
f b x d y = (b x) (d y)
Done.
You can also gradually append arguments to f:
f = ((.) . )
f x = (.) . x
f x y = ((.) . x) y
= (.) (x y)
= ((x y) . )
f x y z = (x y) . z
f x y z t = ((x y) . z) t
= (x y) (z t)
= x y (z t)
= x y $ z t
The result reveals that x and z are actually (binary and unary, respectively) functions, so I'll use different identifiers:
f g x h y = g x (h y)
We can work backwards by "pattern matching" over the combinators' definitions. Given
f a b c d = a b (c d)
= (a b) (c d)
we proceed
= B (a b) c d
= B B a b c d -- writing B for (.)
so by eta-contraction
f = B B
because
a (b c) = B a b c -- bidirectional equation
by definition. Haskell's (.) is actually the B combinator (see BCKW combinators).
edit: Potentially, many combinators can match the same code. That's why there are many possible combinatory encodings for the same piece of code. For example, (ab)(cd) = (ab)(I(cd)) is a valid transformation, which might lead to some other combinator definition matching that. Choosing the "most appropriate" one is an art (or a search in a search space with somewhat high branching factor).
That's about going backwards, as you asked. But if you want to go "forward", personally, I like the combinatory approach much better over the lambda notation fidgeting. I would even just write many arguments right away, and get rid of the extra ones in the end:
BBabcdefg = B(ab)cdefg = (ab)(cd)efg
hence,
BBabcd = B(ab)cd = (ab)(cd)
is all there is to it.

Why does it apply the second argument?

I am trying to understand the Interchange law of applicative functor:
u <*> pure y = pure ($ y) <*> u
What make me confuse is, the function application $ y, consider following example:
($ 2) :: (a -> b) -> b
Why does the second argument get applied not the first?
That's an operator section. A few simple examples:
Prelude> (/2) <$> [1..8]
[0.5,1.0,1.5,2.0,2.5,3.0,3.5,4.0]
Prelude> (:"!") <$> ['a'..'e']
["a!","b!","c!","d!","e!"]
The section (:"!") is syntactic sugar for \c -> c:"!", i.e. it takes a character c and prepends it to the string "!".
Likewise, the section ($ 2) takes a function f and simply applies it to the number 2.
Note that this is different from ordinary partial application:
Prelude> ((/) 2) <$> [1..8]
[2.0,1.0,0.6666666666666666,0.5,0.4,0.3333333333333333,0.2857142857142857,0.25]
Here, I've simply applied the function (/) to one fixed argument 2, the dividend. This can also be written as a left section (2/). But the right section (/2) applies 2 as the divisor instead.
You can do that with operator sections. For example:
(5+ ) -- Same as \ x -> 5+x
( +5) -- Same as \ x -> x+5
It's only operators you can do this with; normal named functions can only be curried from left to right.
Haskell cheat sheet operator sections entry could be:
(a `op` b) = (a `op`) b = (`op` b) a = (op) a b
When op is an actual operator (not an alpha-numerical name), backticks aren't needed.
The above can be seen as partially applying implicitly defined lambda expressions:
(a `op`) b = (a `op` b) = (\y -> a `op` y) b = (\x y -> x `op` y) a b = op a b
(`op` b) a = (a `op` b) = (\x -> x `op` b) a = (\y x -> x `op` y) b a = flip op b a
If a function f expects more than two arguments eventually, we can similarly create its curried version by partially applying an explicit lambda expression:
(\y z x -> f x y z) b c -- = (\x -> f x b c)
(\x z y -> f x y z) a c -- = (\y -> f a y c)
(\x y z -> f x y z) a b -- = (\z -> f a b z)
The last case is equivalent to just f a b, and the second to (flip . f) a c:
g b c a = f a b c = flip f b a c = flip (flip f b) c a = (flip . flip f) b c a
g a c b = f a b c = flip (f a) c b = (flip . f) a c b
g a b c = f a b c

Haskell pattern matching inside parentheses

I would like to define a function that operates on an expression of a certain type, but has access to its internal structure, if it has one. For instance, f in what follows:
g :: a -> a -> a
g x y = y
f :: a -> a
f x'#(g x y) = x'
f _ = 1
(g x y) is of type a, so f should be able to take it as an argument, but the definition for f above can't be parsed by Haskell. I would like to define something like f to take advantage of call-by-name evaluation. Is there any way to do this in Haskell?
First, pattern matching is allowed only on patterns, i.e. expressions built from application, constructors, and variables (used at most once).
Second, even if it were extended, your example is problematic because your g is not injective:
case g x y of g a b -> a
should be equal to, since g x y = y
case y of g a b -> a
but then a could be anything.
If instead it happens that g is defined by an expression which could be a pattern, then GHC can allow using it as a pattern if you ask for it through the PatternSynonyms GHC extension.
pattern G a b = ("hello", b, a)
foo = case someTriple of
G a b -> use a b
(s, x, y) -> ...
bar = G 4 5 -- we can also use G as a function

Type of function to swap arguments of a function

So I made these functions to swap the arguments of functions
swap1_3 f x y z = f z y x
toFront3 f x y z = f z x y
These functions work as follows
foo x y z = [x,y,z]
a = foo 1 2 3 -- returns [1,2,3]
b = swap1_3 foo 1 2 3 -- returns [3,2,1]
c = toFront3 foo 1 2 3 -- returns [3,1,2]
Now, what I don't understand are the type signatures of these functions.
The type signatures are as follows
swap1_3 :: (a -> b -> c -> d) -> c -> b -> a -> d
toFront3 :: (a -> b -> c -> d) -> b -> c -> a -> d
From just looking at
swap1_3
one would think that
a corresponds to the type of x
b corresponds to the type of y
c corresponds to the type of z
d corresponds to the return type of f
but, when you look at the second half of the the type signature of
toFront3
it seems like there isn't that correspondence.
So, what's going on here?
It's a bit confusing, but look at it this way
f :: a -> b -> c -> d
f z :: b -> c -> d
f z x :: c -> d
f z x y :: d
Which implies
z :: a
x :: b
y :: c
So, we have
toFront3
:: (a -> b -> c -> d) -- f
-> b -- x
-> c -- y
-> a -- z
toFront3 f x y z = f z x y
I'm often confused by the types of these sorts of function-transforming functions for a minute before I think about them. Another good way of looking at them is to add unnecessary parentheses to their types, and look at them like this:
toFront3 :: (a -> b -> c -> d) -> (b -> c -> a -> d)
That is, toFront3 takes a function of 3 arguments, and gives you a function of the same arguments in a different order.
To have some names:
let g = toFront3 f
g and f are both functions of 3 arguments. g is going to call f after shuffling its 3rd argument to the front. Therefore the arguments g will receive are the pre-shuffled arguments. So to go from f :: a -> b -> c -> d to the type of g we have to apply the inverse shuffling of arguments that toFront3 does, so that shuffling them will restore the argument order to a -> b -> c -> d, as is required to be passed to f post-shuffle.

Resources