I'm new to Haskell and I'm having a little bit of trouble understanding some of the concepts of the language.
I have the following expression:
\f x → (f x,f 1)
And from my understanding, I can say that:
At first, I can't really say what f is because I have no information,
so I say it can be anything.
Then judging from the application of (f x) I can say that it's a
function of type a->b where x::a
Then judging from the application of (f 1) I can say that a is of
type Integer, therefore x is the same type
Then I don't really understand why the whole expression is of type:
(Integer → b) → Integer → (b, b)
I have a little guess and I'm going to say that:
(Integer → b) is the type of the function f, so it receives and integer and returns a type b
Integer is the type of x
(b b) is the type of the two functions called?
Can someone point me in the right direction please? Thank you
The entire lambda takes a function f, and x as inputs; it produces
a pair; the first element of the pair is the result of applying f to x, the second element is the result of applying f to 1. From f 1, we know that the input to f has to be limited to the Num type class.
getPair :: Num a => (a -> b) -> a -> (b, b)
getPair = \f x -> (f x, f 1)
The only constraint is Num a =>
getPair id 8.9 => (8.9, 1.0)
getPair (\x -> x > 0) (-9.8) => (False, True)
You are correct.
Since f is applied to 1 :: Integer, then f :: Integer -> b.
And since f is also applied to x, then x :: Integer.
And since the result of the lambda is a tuple of applications of f, then the result type is (b, b).
So the type of the lambda is a function that takes something of the type of f to a function that takes an Integer to a tuple of (b, b).
Edit
c b a = a b
Assume b :: t1.
Since a is applied to b, we can say that a :: t1 -> t.
Since the c takes something of the type of b (t1) to something of the type of a (t1 -> t) to the result of the application of a to b (t), we can say that c :: t1 -> (t1 -> t) -> t.
Related
Im trying to wrap my head around Haskell and I'm having trouble trying to implement the following signature as a function. Could you guys give me an example using lambda expressions?
(b -> c) -> (a -> b) -> a -> c
Try with simpler examples first. For example,
f :: a -> a
f = ...
Since f is a function of one argument, we can extend this without thinking much into:
f :: a -> a
f = \x -> ...
Picking a return value for this function, we have exactly one good candidate, x, so:
f :: a -> a
f = \x -> x
although we could also have picked undefined or error "meh", or f x, which are less useful.
Here's another simple example:
g :: (a, b) -> (b, a)
g = ...
The only pattern that matches the function's input is a pair, so:
g :: (a, b) -> (b, a)
g = \(x, y) -> ...
This doesn't have to be equivalent to swap, but it's a good candidate because it terminates.
A last example that is more complicated:
h :: ((a, b) -> c) -> a -> b -> c
h = ...
This is a function of three arguments of types (a, b) -> c, a and b, so without thinking much we can extend the answer partially:
h :: ((a, b) -> c) -> a -> b -> c
h = \f -> \x -> \y -> ...
h = \f x y -> ...
(The lower line is just a convenient way to stack curried arguments.)
Now, I gave them names f, x and y because I think f is a good, generic name for a value that contains an ->, and x and y are good, generic names for arbitrary values. I could also have picked a and b to strengthen the connection between the types of the same name, but it'd also be a little confusing. So here, x :: a and y :: b.
As for filling out the function body, I can either go by asking "How do I apply the things I've got so the types align", or I can look at the return type, c, and look at what I have available to make a value of type c. f returns c if I feed it a pair of type (a, b). I have an x :: a and a y :: b, so (x, y) :: (a, b):
h :: ((a, b) -> c) -> a -> b -> c
h = \f x y -> f (x, y)
This is incidentally curry. I don't think you can find any other solution that terminates?
For simple functions there is often only one good candidate. When you have type signatures with multiple values of the same type, you have to consider what happens if you pick one over the other. The first case I can think of is when you implement the >>= operator for the state monad.
Let's rename our type variables:
a becomes oil
b becomes petrol
c becomes co₂
Now, you already recognised what the arguments to your function are:
implementation (x :: petrol -> co₂)
(y :: oil -> petrol)
(z :: oil)
= (? :: co₂)
It's sort of conventional to name functions f, g... and values a, b... _if we know nothing about the underlying types. Ok, but after we named the types, let's pick appropriate names accordingly:
implementation (car :: petrol -> co₂)
(refinery :: oil -> petrol)
(tankship :: oil)
= (? :: co₂)
Or, in lambda form without the local signatures:
implementation = \car refinery tankship -> ?
I'll leave the rest to you.
This question already has an answer here:
Type Inference in Haskell for functions
(1 answer)
Closed 3 years ago.
I'm preparing for my exams but there is something I can't understand.
functions:
tw f x = f (f x)
f x y = (y, x)
I am able to determine the type of 'f' which is
f :: t1 -> t -> (t, t1)
but can't determine the type of 'tw'.
Supposed type of tw:
tw :: (t -> t) -> t -> t
thanks!
Let us analyze the function tw:
tw f x = f (f x)
tw takes as parameters f and x. At the moment we dot not know much about these parameters, so we will give these as types f :: a and x :: b.
Now we see a function application with f the function and x the parameter. This thus means that f is a function that takes a value of type b (the type of x), and returns something. We thus specify that f has as type f :: b -> c, with c a new type variable we introduce. We thus know that f x :: c.
We furthermore see, that there is a function application with f :: b -> c the function, and f x :: c the parameter. Since the type of the parameter of f is b, and f x has as type c. We thus come to the conclusion, that b and c must be the same type.
This thus means that we derived as types:
x :: b
f :: b -> b
We can furthermore analyze the type of tw f x by determining the type of f (f x). Since f x has type f x :: b, and f has type f :: b -> b, we know that f (f x) has type f (f x) :: b. So that means that the type for tw is:
tw :: (b -> b) -> b -> b
If we substitute b for t, then we obtain the expected type signature. But since b and t are just variables, that does not matter much.
fold function :
fold :: b -> (a -> b -> b) -> [a] -> b
fold z f [] = z
fold z f (x:xs) = f x (fold z f xs)
taken from http://www.seas.upenn.edu/~cis194/spring13/lectures/04-higher-order.html
Prelude> :t (+)
(+) :: Num a => a -> a -> a
*Main> fold (0) (+) [1,2,3]
6
What does type (a -> b -> b) match with type a -> a -> a for (+) function ?
As fold definition accepts function type (a -> b -> b) this means the first 2 parameters (a -> b) are required to be of different types ?
No, all it means is that a and b can be different, but it isn't mandatory for it to be different. In your case, it is the same.
A much simpler example to convey the point:
data SomeType a b = Test a b deriving (Show)
Now in ghci:
λ> :t Test
Test :: a -> b -> SomeType a b
λ> let x = Test (3 :: Int) (4 :: Int)
λ> :t x
x :: SomeType Int Int
You are thinking in reverse direction. You do not have to check whether + is identical or matches a -> b -> b, you want the type of + to be a specialization of a -> b -> b and to check this you have to unify the types.
Unification means that you want to see whether the type of + and the type a -> b -> b can be made equal by renaming the type variables.
So + has type Num x => x -> x -> x. Let's ignore the class constraint for now, and let's see if we can match the functional types.
The types become x -> x -> x and a -> b -> b. In fact it's better if we look at them as they really are, without using associativity: x -> (x -> x) and a -> (b -> b).
The -> is a type constructor. I.e. it is a function that maps a certain number of types to a different type. In this case the -> constructor maps two types t_1 and t_2 to the functional type (->) t_1 t_2 (which is usually denoted by t_1 -> t_2).
So the type x -> (x -> x) is actually (->) x ((->) x x) which is the type constructor -> applied to x and to the type constructor -> applied to x and x.
The other type is (->) a ((->) b b).
When unifying you consider the outermost type constructor for the two types (-> for both in this case). If this doesn't match, you cannot unify.
Otherwise you have to unify the arguments of the constructor.
So we have to unify x with a. They are both type variables, so we can rename one of them. Let's say that we rename a with x. So now we apply the renaming to the types, obtaining: (->) x ((->) x x) and (->) x ((->) b b) and you see that x and x now match.
Let's consider the second argument. It's not a type variable so we have to match the type constructor, and this is again -> for both. So we procede recursively on the arguments.
We want to match x and b. They are both type variables, so we can rename one of them. Say we rename x to b. We apply this substitution to the types, obtaining: (->) b ((->) b b) and (->) b ((->) b b). Now the everything matches. Hence the two types unify.
Regarding the class constraint, when we rename x with b we applied the substitution to the constraint too so Num x became Num b and the two final types are both Num b => b -> b -> b.
I hope this gave you some better understanding on how the types work and how the types are checked.
Side note: This is what haskell does when performing type inference. It first assign to an unknown function a fresh type variable t. Then it uses unification to obtain the type of the expression that defines it and check what type was associated with t, and this is the type of the function.
I have the applicative <$> operator more or less figured out, but I can't understand the signature I'm getting with the following example:
ghci> let f x y z = x + y + z -- f::Num a => a -> a -> a -> a
ghci> f <$> Just 2 <*> Just 3 <*> Just 4
Just 9
This result I understand, but when checking the following type:
ghci> :t (<$> f)
(<$> f) :: Num a => ((a -> a -> a) -> b) -> a -> b --This makes no sense to me
That signature I would understand as : a function that takes a (a -> a- > a) -> b function and an a as parameters and returns a b. According to this reasoning , I should call this like :
(<$>f) f 4
which would result in an Integer.
Obviously this is not true, so can you please help me understand how to read the type of (<$> f)?
a function that takes a (a -> a- > a) -> b function and an a as parameters and returns a b.
This is correct.
According to this reasoning , I should call this like :
(<$>f) f 4
which would result in an Integer.
No, because f does not have type (a -> a -> a) -> b or one compatible with it. Instead it has type Num a => a -> a -> a -> a. That is, f takes three numbers and produces a number, whereas we're looking for a function that takes a function (of type a -> a -> a) as its first argument.
<$> takes as a second argument something of type g b, where g is any applicative functor.
You are passing f :: Num a => a -> a -> a -> a as a second argument. Let's ignore the Num a context to keep things simple.
Hence, we look for g,b such that g b = a -> a -> a -> a.
Let's write the type of f in prefix form:
f :: (->) a ((->) a ((->) a a)) = g b
Hence, g = (->) a and b = ((->) a ((->) a a)). The latter is b = a -> a -> a in infix form.
It happens that (->) a is an applicative functor, so <$> f type checks. Note however that <$> is used on a completely different functor than the Maybe one you were using in your examples. Hence the confusion.
TL;DR: overloaded identifiers can shapeshift to many things adapting to their contexts, possibly in some unexpected way.
Having troubles with manually calculating types of given functions in Haskell for an exam at the weekend.
I understand the basics such as:
i x = x :: t -> t
k x y = x :: t -> t1 -> t
But having trouble on more complicated questions such as:
two f x = f (f x)
s x y z = x z (y z)
Any explanations would be much appreciated!
In those two examples the only hints you have as to the types of the functions come from observing the application going on. In Haskell application hardly has any syntax, so I'll rewrite them a bit more obviously.
two f x = f(f(x))
s x y z = x(z)(y(z))
We'll now discover the types of these functions through gradual refinement. For instance, beginning with two we know that it takes in two arguments and thus must have a type which agrees with the (more general) type
two :: a -> b -> c
We also know that the a type variable above actually corresponds to a function because f is being applied to both x and f(x).
two :: (a -> b) -> c -> d
Since f is applied to x we know that here a and c must be the same.
two :: (a -> b) -> a -> d
and since we apply f again to its result f(x) we know that the result type must be the same as the input type
two :: (a -> a) -> a -> b
And finally, the result of calling f is the total result of two so d must also equal a
two :: (a -> a) -> a -> a
This uses all of the information we have in the definition and is the most general type that is compatible with the definition of two.
We can do basically the same process for s. We know it has 3 arguments
s :: a -> b -> c -> d
We know that the first and second arguments are functions of some kind. We see the second argument applied to a single value and the first applied to two values.
s :: (a -> b -> c) -> (d -> e) -> f -> g
We also know that the first input to both functions are the same (namely, it's z each time). This lets us infer that a, d, and f are the same type
s :: (a -> b -> c) -> (a -> d) -> a -> e
We also know that the result of calling the second function is the second argument to the first function, so b and d must be the same.
s :: (a -> b -> c) -> (a -> b) -> a -> e
Finally, the result of fully applying the first function is the final result of s so c and e are the same
s :: (a -> b -> c) -> (a -> b) -> a -> c
While that might be a lot to digest and kind of a blur, the thing to emphasize is that the tools I've used to solve this problem are all primitive. Effectively, I introduce arrows (->) when I see that the type got applied to some values and thus must be a function of a certain number of arguments and I unify type variables by following the values through their expression. These are sufficient tools for inferring the types of simple functions like two and s.
Your two and s are what as known as higher level functions, because they take functions as arguments. You already have the tools to discern their types, you just have to be willing to be a bit more abstract about it.
If you're given the expression
f x
You know the type of f is a -> b with x :: a and f x :: b. If you see
f (f x)
Then you can deduce that the output type of (f x) is the same as the input type for f. This means that a ~ b, so f :: a -> a and x :: a. If we look at the type of two, we can deduce that it follows the pattern
two :: s -> t -> u
but the first argument to two is f, which has the type a -> a, so we can plug that in as
two :: (a -> a) -> t -> u
And x is the second argument with type a, so we can plug that in
two :: (a -> a) -> a -> u
And the return type is the same as the return type of f (f x), which has the return type of f, which has the return type of a, so if we plug that in we get the final type
two :: (a -> a) -> a -> a
For s, we can do similarly. We start off by saying s follows the form
s :: s -> t -> u -> v
since it has 3 arguments. The expression (y z) is function application, so y must have the type y :: a -> b, with z :: a. Plugging that in to s:
s :: s -> (a -> b) -> a -> v
Then we look at x z (y z). Since y z :: b and z :: a, x is a function of two arguments, the first of type a and the second of type b, with some unknown return type c, so we can plug that in as
s :: (a -> b -> c) -> (a -> b) -> a -> c
Let's look at
two f x = f (f x)
We will proceed by writing down what we know, using variables for anything we don't. Some of the things we know will be equations, and like in math, we will substitute around in the equations until we get something that we can't do anything else with.
Starting with the expression f x. f is a function, and its argument type is whatever x's type is, so:
x :: a -- a is a new variable
f :: a -> b -- b is a new variable
These two equations say exactly what I just said in the previous sentence. Also, we created the variable b which is the type of the result of the application:
f x :: b
Now let's move on to f (f x). So the argument type of f has to be the type of f x, which we know is b, so:
f :: b -> c -- c is a new variable
f (f x) :: c
But, of course, a function can only have one type, and we already have a type for f:
f :: a -> b -- from above
That means that
a = b
b = c
We've reached the top level expression now. So now let's look at the types of the input variables we've found together with the expression:
f :: a -> b
x :: a
f (f x) :: c
Now we go substituting around as much as we can, expressing it with as few variables as possible (but only using equalities that we have deduced). We'll try to do it all in terms of a.
f :: a -> b
= a -> a -- because b = a
x :: a
f (f x) :: c
= b -- because c = b
= a -- because b = a
And there we have it:
two :: (a -> a) -> a -> a
^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^
type of f type of x type of result
This is more verbose than necessary, because I repeated myself a lot, so that you could see the reasoning involved. There is a methodical way to do this, but I prefer to do it more like math, going along and discovering what I can. The methodical way usually gets me lost in a sea of variables (which is easy enough for a computer, but hard for my mortal human brain).
I hope this helped.