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.
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
First of all, sorry if I'm not not posting this on the correct site since I'm not sure if it's more of a mathematical question than a programming one, but since I'm using this with Haskell and comparing the results with a Haskell interpreter, I just thought I'd ask it here.
So I'm basically trying to evaluate lambda expressions in Haskell and I'm doing it manually (in preparation for an exam, since I'll be forced to do it on paper). I'm given some expressions and I have to write down their general types after they're evaluated. To do so, I'm using an interpreter to get a somewhat correct answer.
In particular, I'm going to evaluate the following expressions:
t2 = ( \x y z -> y.x.y );
tx2 = (\x y z -> y.z.z);
tp2 = (\x -> \y -> (x.y.x));
td2 = (\x y z f -> y(z(z(f))));
tm2 = (\z -> \y -> \x -> z.y.x);
Since I don't 100% understand how to do this, I've devised a method. First, I create a template that somewhat resembles what the evaluated expression will look like. I.E. if part of the left-size ('lambda'd') variable is featured on the right side (as it's pretty much functional composition in every case), it's a function. If not, it's just a variable. Afterwards, I'm trying to fit the general types of the functions as best as I can and I'm getting some semi-right results, but I'm sure I'm still making some mistakes. Here's my whole evaluation process:
t2 = ( \x y z -> y.x.y );
(_ -> _) -> (_ -> _) -> c -> _ -> _
y(x(y))
assume:
y :: a -> b
x :: b -> a
result: (b -> a) -> (a -> b) -> c -> a -> b
interpreter: (a -> b) -> (b -> a) -> c -> b -> a
z isn't featured on the right side, so it's not a function in this case. I'm assigning it c. Now I'm looking at the composition on the right side. I'm going right to left and I assign a -> b to y since I have no idea about it's input or output. Since x uses the result of y as an input, and y uses x' output as an input again, x is b -> a. Which I can just insert into my template.
As you can see, it's not exactly the same result as I get via the interpreter, but it's only a and b being switched around, so it doesn't seem that wrong.
tx2 = (\x y z -> y.z.z);
a -> (_ -> _) -> (_ -> _) -> _ -> _
y(z(z))
assume:
z :: b -> b
y :: b -> c
result: a -> (b -> c) -> (b -> b) -> b -> c
interpreter: a -> (b -> c) -> (b -> b) -> b -> c
Same as above. Since z uses itself in functional composition, I assume it has the same input and output. y uses z's output as input and has some unknown output, hence c. This appears to be in line with my interpreter.
tp2 = (\x -> \y -> (x.y.x));
(_ -> _) -> (_ -> _) -> _ -> _
x(y(x))
assume:
x :: a -> b
y :: b -> a
result: (a -> b) -> (b -> a) -> a -> b
interpreter: (a -> b) -> (b -> a) -> a -> b
Pretty much the same as the first example, only I don't have an unused lambda variable.
td2 = (\x y z f -> y(z(z(f))));
a -> (_ -> _) -> (_ -> _) -> (_ -> _) -> _ -> _
y(z(z(f)))
assume:
f :: _ -> b
z :: b -> b
y :: b -> c
assume: a -> (b -> c) -> (b -> b) -> (_ -> b) -> b -> c
result: a -> (b -> c) -> (b -> b) -> (b -> b) -> b -> c
interpreter: a -> (b -> c) -> (b -> b) -> b -> c
Everything but x is a function in this case. f's Input isn't initially known to me and I'm just leaving it empty at the time. z uses f's output and it's own output in composition, so I just assign it b -> b. y uses z's output, and has an unknown output itself, so it gets b -> c.
Now I insert it into my template, but I'm still missing an input for f. Since there's a b right after f, I just assume it uses b as an input, too.
Now there's the first real question: where did f disappear to in the answer given by the interpreter? I can only assume since it uses the same input/output as z and it's basically in composition with it, it just got simplified into a single b->b, but I'm not sure about this.
tm2 = (\z -> \y -> \x -> z.y.x);
tm2 = (\z y x -> z.y.x);
(_ -> _) -> (_ -> _) -> (_ -> _) -> _ -> _
z(y(x))
assume:
x = a -> b
y = b -> _
z = _ -> _
assume: (_ -> _) -> (b -> _) -> (a -> b) -> _ -> _
result?: (a -> c) -> (b -> a) -> (a -> b) -> a -> c
interpreter: (a -> b) -> (c -> a) -> (d -> c) -> d -> b
Here's where it all falls apart: z, y, and x are functions. So I'm just assigning a -> b to x, which means that y's input is b. The output is unknown to me at this time. Same goes for z, since I have no idea about y's output.
So after I enter them in my template, the only thing that's really left for me is just to fill in the blanks for unknown values. Since x would require a as input, it means that there's an a right after it. Which would mean that it's z's input, too. Since it's z's input, I can assume it's y's output. The only thing left to fill in is z's output, and I just assign it a c since I don't really know what it could be.
As you can see, this isn't what the interpreter gives me, at all. While the left hand side might be still somewhat similar, I don't understand what happens on the right hand side, at all. Why is it d -> b? Shouldn't it be whatever's the result of (z(y(x))), which should have z's input/output?
Thanks in advance for any help you might offer me.
There are three basic properties you can exploit:
Due to currying, \x y -> z is equivalent to \x -> \y -> z.
For any x(y), you know that x must be a function and its first argument matches the type of the expression y.
You know the type of ., which is (b -> c) -> (a -> b) -> a -> c. Furthermore, . is right-associative (i.e. a.b.c is the same as a.(b.c)).
With this in mind, consider your first example:
t2 = ( \x y z -> y.x.y );
Clearly, it's a function of three arguments, so its type will be something akin to
t2 :: ty0 -> ty1 -> ty2 -> ty3
I use ty0 through ty3 here to denote the types to infer. ty0 is the type of the x argument, ty1 is for y, ty2 for z and ty3 is the type of the result value (i.e. the type of the expression y.x.y).
I'd start with determining the type ty3 (which is defined by the expression y.x.y) because while doing so you'll also find the types of the used arguments. Unused arguments can have any type:
y.x.y is equivalent to y.(x.y) (due to right-associativity of ., see item #3 above). So you can start by considering the subexpression x.y.
This means that x :: (b -> c) and y :: (a -> b) and hence x.y :: a -> c (due to the type of ., again see #3 above).
So we know that y :: (a -> b) and x.y :: a -> c. With this in mind, the only way y.(x.y) can type check (i.e. match the type of .) is when c ~ a, i.e. c and a are the same type.
Hence, x :: b -> a (our ty0!) and y :: a -> b (ty1) andy.(x.y) :: a -> b(what we calledty3` above). You can plug this into our primitive 'three-argument function type' above.
t2 :: ty0 -> ty1 -> ty2 -> ty3
=>
t2 :: (b -> a) -> (a -> b) -> ty2 -> (a -> b)
...and since -> is right-associative, you can omit the last parens (and instead of ty2 you could have used c, of course).
Let's try the same strategy on your last example:
tm2 = (\z -> \y -> \x -> z.y.x);
This is equivalent to \z y x -> z.y.x (due to currying, see #1 in the list at the top).
This means it's another three-argument function of the form tm2 :: ty0 -> ty1 -> ty2 -> ty3. Again, we start by inferring the type ty3 by considering the definition of the function.
The type ty3 is the type of the expression z.y.x, which is equivalent to z.(y.x) (due to right-associativity of .).
All three variables must be functions to satisfy the type of . (see #3 in the list at the top).
So x :: a -> b, y :: b -> c, y.x :: a -> c.
From this, it follows that z :: c -> d and hence z.y.x :: a -> d.
Since z is the first argument to tm2, y is the second and x is the third argument, you can tell that
tm2 :: (c -> d) -> (b -> c) -> (a -> b) -> (a -> d)
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.
How can I use curry and uncurry prelude functions in Haskell?
Moreover, why do the following definitions throw an error when loaded?
curry' :: ((a -> b) -> c) -> a -> b -> c
curry' f = \x y -> f (x, y)
uncurry' :: a -> b -> c -> ((a -> b) -> c)
uncurry' f = \(x,y) -> f x y
You're getting errors because your type signatures are wrong, you should be using tuples instead of functions for the a and b arguments:
curry' :: ((a, b) -> c) -> a -> b -> c
uncurry' :: (a -> b -> c) -> ((a, b) -> c)
Also, notice the parentheses I added to uncurry's type, those are important in this case. What you have is equivalent to
uncurry' :: a -> (b -> (c -> ((a -> b) -> c)))
Which is not the same, this is a function that takes 3 arguments and produces a function instead of a function that takes a 2 argument function and returns a function of one tuple argument.
You could use these functions like
> uncurry (+) (1, 2)
3
> curry fst 1 2
1
> curry snd 1 2
2
(I didn't see any other Prelude functions that take tuples as arguments)
EDIT: At chi's request, here's a more visual explanation of that last sentence:
a -> (b -> (c -> ((a, b) -> c)))
is the type of a function that takes 3 arguments a, b, and c, and returns a function of type (a, b) -> c.
(a -> b -> c) -> ((a, b) -> c)
is the type of a function that takes a single argument a -> b -> c and returns a function (a, b) -> c.
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.