I am a little confused about what the "partial" application of flip might do.
Since the type of the flip function is:
flip :: (a -> b -> c) -> b -> a -> c
which we can write without the parenthesis as:
flip :: a -> b -> c -> b -> a -> c
How can I partially apply it to only the first argument a? To get a function with the type:
flipa :: b -> c -> b -> a -> c
Or it doesn't make sense?
For example if I have something like:
let foo a b = (Just a, b)
:t foo
> foo:: a -> t -> (Maybe a, t)
It makes sense to partially apply it:
let a = foo 1
:t a
a :: t -> (Maybe Integer, t)
It doesn't make sense. The signature
f :: a -> b -> c
is equivalent to
f :: a -> (b -> c)
and not equivalent to
f :: (a -> b) -> c
This convention is why you can partially apply function in Haskell in the first place. Since all functions are curried by default, the signature f :: a -> b -> c can be interpreted as
f takes a and b, and returns c
or can equally validly be interpreted as
f takes a, and returns a function that takes b and returns c
(a -> b -> c) -> b -> a -> c is not the same as a -> b -> c -> b -> a -> c because the -> operator is right-associative, not left-associative. Therefore, partially applying flip is meaningless because it only has one parameter in the first place.
Also, your example doesn't make much sense because it would still produce an output function taking an a, which you would presumably not want. But if you take that out, you get a function which takes a unary function and produces exactly the same unary function, so just partially apply the original function and you're done.
As others have noted, the type (a -> b -> c) -> b -> a -> c is not the same as a -> b -> c -> b -> a -> c.
However, it is the same as (a -> b -> c) -> (b -> a -> c).
That shows that flip is a function that takes a single argument as input and therefore can't be partially applied*.
*: from the point of view of that flip returns a function of type b -> a -> c, which is not the only valid point of view in Haskell.
Related
This compiles successfully:
test = f id
f :: (a -> b -> c) -> String
f g = "test"
id has type a -> a, but f have a first argument of type (a -> b -> c).
I think it should not compile. I cannot understand it.
Because you can bind the uninstantiated variable. f :: (a -> b -> c) -> String says that for any 3 types a, b and c, f takes a function from a to b to c and returns string.
Its important to remeber that f :: (a -> b -> c) -> String is equivalent to f :: (a -> (b -> c)) -> String because of currying.
id takes any type, and returns that type.
So if we swap that in, id is returning b -> c, and taking a, so if a can be b -> c which it can as a can be any type, then this is fine.
Short version: it works because id can take and return functions -- and so can behave as if it were a two-argument function. Now for the long version.
id is a function that takes a value and returns it unchanged. Because it's so simple, it can do that for all kinds of different values -- Ints and Bools and Strings and lists and trees...
id :: Int -> Int
id :: Bool -> Bool
id :: String -> String
id :: [(b, c)] -> [(b, c)]
id :: Tree b -> Tree b
id :: (b -> c) -> (b -> c)
...and functions, why not!
f is a function that takes two-argument functions and ignores them. Because its handling of the function you give it is so simple, it can do that for all kinds of different two-argument functions -- addition, concatenation, pairing, ignoring, printing...
f :: (Int -> Int -> Int) -> String
f :: ([b] -> [b] -> [b]) -> String
f :: (b -> c -> (b, c)) -> String
f :: (b -> c -> b) -> String
f :: (Handle -> String -> IO ()) -> String
f :: ((b -> c) -> b -> c) -> String
...and the operation that takes a function and an argument and applies the one to the other, why not!
Ah, but two argument functions are really just one-argument functions that themselves return a function. So these two types are really just different spellings of the same type:
(b -> c) -> (b -> c)
(b -> c) -> b -> c
And, it turns out, the two behavior descriptions I gave for these two types also turn out to be the same. Recall they were:
A function that takes a function as an argument and returns it unchanged.
A function that takes a function as an argument, and an argument for that function, and applies one to the other.
I'll let you stew for a bit on why those turn out to be the same!
In any case, at this point it should be much more clear why this works. And, for the mechanical version of the answer, we can take these two types:
id :: a -> a
f :: (a -> b -> c) -> String
and make them fit together by choosing a ~ b -> c for both. (It is just a coincidence that the two instantiations of a are to the same type -- this is not generally the case when doing unification!) After instantiating a to b -> c in both type signatures, we get:
id :: (b -> c) -> b -> c
f :: ((b -> c) -> b -> c) -> String
lets say I have:
t = \x y -> x.y
its type is then:
*Main> :t t
t :: (b -> c) -> (a -> b) -> a -> c
If I understood correctly, x.y could be written as x(y), which means we first solve y which is (b -> c) and then x which is (b -> a) and a -> c is just are parameters in function; We give a (x) and c (y). Is this correct? If not how do I read this? what does (b -> c) -> (a-> b) mean and which one is x which one y.
And how do I read this:
t1 = \x y z -> x.y.z
*Main> :t t1
t1 :: (b1 -> c) -> (b2 -> b1) -> (a -> b2) -> a -> c
What is here b1 what b2 and how does this exactly work? Why is at the and just a -> c when I have 3 parameters as input? Please help me understand this
A better way to write the function type (b -> c) -> (a -> b) -> a -> c would be (b -> c) -> (a -> b) -> (a -> c) where there are explicit parentheses around (a -> c). This rewriting attempts to make it clear that the function does not take three arguments and return something of type c. It takes two arguments and returns a function of type (a -> c). This is the concept of currying, and it is integral to Haskell programming1.
In your first example, (b -> c) is x and (a -> b) is y. The return type (a -> c) is the new function obtained by composing the parameter functions.
Your second example can be interpreted in the same way. (b1 -> c) corresponds to x, (b2 -> b1) to y and, (a -> b2) to z. The return type is obtained by first composing z and y to get a function of type (a -> b1) then composing this function with a to get a function of type (a -> c). This function is what is ultimately returned.
1: In fact it is most correct to say that the function takes one argument of type (b -> c) and returns a function of type (a -> b) -> (a -> c) but, that's not particularly important.
I have to define the type profile of this function:
twice f x = f (f x);
The result should be the following, but I don't really get why.
('a -> 'a) -> 'a -> 'a
(a -> a) -> a -> a is the right answer. Let's split it to pieces to find out why.
your function takes two arguments, f and x, so the signature will have three parts - say, a -> c -> d
first of these arguments is an unary function - that makes a = (a -> b) (remember that a can be any type, as long as it appears only once in the signature) and the signature look like (a -> b) -> c -> d
result of twice is same as the result of its first argument - that makes d = b and the signature (a -> b) -> c -> b
f takes second argument of twice as its argument - this makes c = a and the signature look like this: (a -> b) -> a -> b
twice is applied to its own output, which means that a = b - this makes the final signature (a -> a) -> a -> a
I know the title is a bit unclear, the problem is:
Suppose I have a function of type a -> c, another function of type b -> d, how can I get a function of type (a -> b) -> (c -> d), or is it impossible in general?
Probably I should provide some background. I asked this question because I have difficulty solving Exercise 9 from the paper Fun with phantom types.
data Type t where
...
RFun :: Type a -> Type b -> Type (a -> b)
And the tequalfunction
tequal :: Type t -> Type u -> Maybe (t -> u)
...
tequal (RFun a b) (RFun c d) = -- should do something with (tequal a c) (tequal b d)
So the problem boils down to composing a -> c and b -> d to get (a -> b) -> (c -> d)
This is impossible.
Suppose you have desired function f :: (a -> b) -> (c -> d).
You can simplify it's type to (a -> b) -> c -> d (See why).
How could implementation of f look like? It has first argument of type a -> b and second of type c:
f ab c = ...
What can you do with ab? It's a function but you can't apply it because you don't have anything of type a (except _|_). And even if you have functions g :: a -> c and h :: b -> d they are of no use because you don't have anything of type a or b and you can't compose them.
So the only valid implementation is something like
f ab = undefined
or
f = undefined
Regarding second part of your question, it seems that you can recursively use tequal to check function type equality: types a -> c and b -> d are equal only if a = b and c = d (this is valid because toy type system from the paper don't have type variables).
Here is a sketch of implementation:
tequal (RFun a c) (RFun b d)
= liftM2 func (tequal a b) (tequal c d)
You can note that the code is almost identical to the case for RPair. This is somehow related to currying.
As a small supplement to max taldykin's answer,
Given
f :: (a -> c) -> (b -> d) -> (a -> b) -> (c -> d)
f ac bd ab = ???
there's really only one way to combine the arguments
bd . ab :: a -> d
but now we're stuck! We have no way to construct a c -> d from any combination of a -> c, b -> d, a -> b, or a -> d.
On the other hand, if we had a c -> a then we could construct a
f :: (c -> a) -> (b -> d) -> (a -> b) -> (c -> d)
f ca bd ab = bd . ab . ca
By the way, it can be very helpful to get out a pen and paper and draw some arrows and try to connect them into a diagram:
If you try to do the same for f :: (a -> c) -> (b -> d) -> (a -> b) -> (c -> d) then you'll see that there's no way to draw a diagram that connects c -> d:
and now we have no way to connect the dots.
I believe that you are looking for Higher Order Functions, which is basically a function taking functions as parameters or returning other functions.
For example to illustrate a higher order function, you can define the following functions:
f0 :: Int -> Int
f0 x = 0
f1 :: a -> a
f1 x = x
f2 :: (a -> a) -> a -> a
f2 f a = f(a)
f3 :: (a -> a) -> (a -> a)
f3 f = f1
Notice that f2 takes a function and apply it to the second parameter and that f3 takes a function and return the function f1.
If you execute f2(f3(f0)) 5, it is going to return 5 to you.
Step-by-step
1- f2(f3(f0)) 5 f3 takes a function (f0) and will return f1.
2- f2(f1) 5 f2 takes a function (f1) and applies it to the second parameter (5)
3- f1(5) f1 is applied to 5.
Given:
uncurry :: (a-> b -> c) -> (a,b) -> c
id :: a -> a
Invoking uncurry id results in a function of type: (b -> c, b) -> c
How do we get this result?
How can you use id (a -> a) as the first parameter to uncurry, which requires a (a -> b -> c) function?
It's easier to understand if we try and look at it from the point of making the types work out: figuring out what we need to do to id's type to get it to fit the shape required by uncurry. Since we have:
id :: a -> a
we also have:
id :: (b -> c) -> (b -> c)
This can be seen by substituting b -> c for a in the original type of id, just as you might substitute Int instead when figuring out the type of id 42. We can then drop the parentheses on the right-hand side, since (->) is right-associative:
id :: (b -> c) -> b -> c
showing that id's type fits the form a -> b -> c, where a is b -> c. In other words, we can reshape id's type to fit the required form simply by specialising the general type it already has.
Another way to understand this is to see that uncurry ($) also has the type (b -> c, b) -> c. Comparing the definitions of id and ($):
id :: a -> a
id a = a
($) :: (a -> b) -> a -> b
($) f x = f x
we can make the latter definition more point-free:
($) f = f
at which point the fact that ($) is simply a specialisation of id to a more specific type becomes clear.
How can you use id (a -> a) as the first parameter to uncurry, which requires a (a -> b -> c) function?
Actually, uncurry requires (a -> (b -> c)) function. Can you spot the difference? :)
Omitting parentheses is evil (well, sometimes). It makes it impossible for a novice to decipher Haskell. Of course after you've gathered some experience with the language, you feel like you don't need them at all, anymore.
Here, it all becomes clear once we write out all the omitted parentheses back explicitly:
uncurry :: (a -> (b -> c)) -> ((a,b) -> c)
id :: a -> a
Now, writing uncurry id calls for a type unification of a1 -> a1 with a2 -> (b -> c). This is straightforward, a1 ~ a2 and a1 ~ (b -> c). Just mechanical stuff, no creative thinking involved here. So id in question actually has type a -> a where a ~ (b -> c), and so uncurry id has type (b -> c,b) -> c, by simple substitution of a ~ (b -> c) into (a,b) -> c. That is, it expects a pair of a b -> c function and a b value, and must produce a c value.
Since the types are most general (i.e. nothing is known about them, and so there's no specific functions to call that might do the trick in some special way), the only way to produce a c value here is to call the b -> c function with the b value as an argument. Naturally, that's what ($) does. So uncurry id == uncurry ($), although id is most certainly not ($).