So I was playing around with Haskell today, thinking about autogeneration of function definitions given a type.
For example, the definition of the function
twoply :: (a -> b, a -> c) -> a -> (b, c)
is obvious to me given the type (if I rule out use of undefined :: a).
So then I came up with the following:
¢ :: a -> (a ->b) -> b
¢ = flip ($)
Which has the interesting property that
(¢) ¢ ($) :: a -> (a -> b) -> b
Which brings me to my question. Given the relation =::= for "has the same type as", does the statement x =::= x x ($) uniquely define the type of x? Must x =::= ¢, or does there exist another possible type for x?
I've tried to work backward from x =::= x x ($) to deduce x :: a -> (a -> b) -> b, but gotten bogged down.
x =::= x x ($) is also true for x = const, which has the type a -> b -> a. So it does not uniquely identify the type.
I'd just like add that you should look at http://hackage.haskell.org/package/djinn. It can take many type signatures and derive an implementation from them. If there's only one implementation possible for a type that djinn understands, it will produce it.
From the equation above, we can determine some of a type signature for x. X need not have this type, but it needs to at least unify with this type.
$ :: forall a b. (a -> b) -> a -> b
x :: t1 -> ((a -> b) -> a -> b) -> t1
Given that, it should be straightforward to write a multitude of implementations of x.
Related
I am writing a function called mapper2 that applies a function to two lists:
mapper2 :: (a-> b -> c) -> [a] -> [b] -> [c]
mapper2 f (x:xs) (y:ys) = (f x y) : (mapper2 f xs ys)
mapper2 _ _ _ = []
I am able to compile the function but get an error when I apply it:
*Main> mapper2 (\x -> x*2) [2,4] [4,6]
<interactive>:4:1: error:
• Non type-variable argument in the constraint: Num (b -> c)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall b c. (Num (b -> c), Num b) => [c]
Can someone explain to me how to fix this and what the error means?
Silvio Mayolo has covered the main, practical part of the question, so I will stick to the technical details related to...
what the error means?
To begin with, the error is a bit hairy, but one thing that you can focus on at first is the Num (b -> c) bit. It indicates that you are somehow trying to use a function type (b -> c) as a number (i.e. an instance of Num), which is something that is almost never done intentionally (as we usually do not use functions as numbers). More often than not, when such things happen it is a sign that there is a mismatch in the number of arguments somewhere (which is the case here, as explained by Silvio Mayolo's answer). That said, what follows is an explanation of how the error comes about.
The first argument of mapper2 has type a -> b -> c or, equivalently, a -> (b -> c). When you pass...
(\x -> x * 2) :: Num z => z -> z
... to it, a -> (b -> c) and Num z => z -> z are matched (or, using the jargon, unified), so that the first z becomes a and the second z becomes b -> c. Since both z are supposed to be the same thing, a becomes b -> c as well, and so the type of (\x -> x * 2) is specialised to:
(\x -> x * 2) :: Num (b -> c) => (b -> c) -> (b -> c)
The error message Non type-variable argument in the constraint: Num (b -> c)
refers to how, unlike in e.g. Num x, there is something within the constraint that is not a type variable. In this case, it is function type constructor, ->. While turning on the FlexibleContexts extension, as the error message suggests, would allow that, there is no reason to do so here, as it still wouldn't be what you want (you have no intention of using functions as numbers). Furthermore, doing so in this case would just lead to another type error.
Look at mapper2's type.
mapper2 :: (a -> b -> c) -> [a] -> [b] -> [c]
Now look at the type of the function you're passing in.
(\x -> x * 2) :: Num a => a -> a
The mapper2 function expects a function of two arguments to be passed in, but your lambda only takes one argument.
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.
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.
I'm doing some excersises where I have to add a function's type and explain what it does. I'm stuck with this:
phy = uncurry ($)
The type, according to GHCi is phy :: (a -> b, a) -> b. My haskell knowledge is basic so I really have no idea what it does.
Let's spell out the type part systematically. We'll start with the types of uncurry and ($):
uncurry :: (a -> b -> c) -> (a, b) -> c
($) :: (a -> b) -> a -> b
Since the target expression has ($) as the argument of uncurry, let's line up their types to reflect this:
uncurry :: (a -> b -> c) -> (a, b) -> c
($) :: (a -> b) -> a -> b
The whole type of ($) lines up with the first argument type of uncurry, and the argument and result types of ($) line up with those of uncurry's first argument as shown. This is the correspondence:
uncurry's a <==> ($)'s a -> b
uncurry's b <==> ($)'s a
uncurry's c <==> ($)'s b
This is kinda confusing, because the a and b type variables in one type are not the same as in the other (just like the x in plusTwo x = x + 2 is not the same as the x in timesTwo x = x * 2). But we can rewrite the types to help up reason about this. In simple Haskell type signatures like this, any time you see a type variable you can replace all of its occurrences with any other type get a valid type as well. If you pick fresh type variables (type variables that don't appear anywhere in the original), you get an equivalent type (one that can be converted back to the original); if you pick a non-fresh type you get a specialized version of the original that works with a narrower range of types.
But anyway, let's apply this to the type of uncurry::
-- Substitute a ==> x, b ==> y, c ==> z:
uncurry :: (x -> y -> z) -> (x, y) -> z
Let's redo the "line up" using the rewritten type:
uncurry :: (x -> y -> z) -> (x, y) -> z
($) :: (a -> b) -> a -> b
Now it's obvious: x <==> a -> b, y <==> a and z <==> b. Now, substituting uncurry's type variables for their counterpart types in ($), we get:
uncurry :: ((a -> b) -> a -> b) -> (a -> b, a) -> b
($) :: (a -> b) -> a -> b
And finally:
uncurry ($) :: (a -> b, a) -> b
So that's how you figure out the type. How about what it does? Well, the best way to do that in this case is to look at the type and think about it carefully, figuring out what we'd have to write to get a function of that type. Let's rewrite it this way to make it more mysterious:
mystery :: (a -> b, a) -> b
mystery = ...
Since we know mystery is a function of one argument, we can expand this definition to reflect that:
mystery x = ...
We also know that its argument is a pair, so we can expand a bit more:
mystery (x, y) = ...
Since we know that x is a function and y :: a, I like to use f to mean "function" and to name variables the same as their type—it helps me reason about the functions, so let's do that:
mystery (f, a) = ...
Now, what do we put in the right hand side? We know it must be of type b, but we don't know what type b is (it's actually whatever the caller chooses, so we can't know). So we must somehow make a b using our function f :: a -> b and value a :: a. Aha! We can just call the function with the value:
mystery (f, a) = f a
We wrote this function without looking at uncurry ($), but it turns out that it does the same thing as uncurry ($) does, and we can prove it. Let's start with the definitions of uncurry and ($):
uncurry f (a, b) = f a b
f $ a = f a
Now, substituting equals for equals:
uncurry ($) (f, a) = ($) f a -- definition of uncurry, left to right
= f $ a -- Haskell syntax rule
= f a -- definition of ($), left to right
= mystery (f, a) -- definition of mystery, right to left
So one way to attack a type that you don't understand in Haskell is to just try and write some code that has that type. Haskell is different from other languages in that very often this is a better strategy than trying to read the code.
uncurry :: (a -> b -> c) -> (a, b) -> c
($) :: (a -> b) -> a -> b
uncurry ($) :: (a -> b, a) -> b
If you inspect types of uncurry and $ and its description:
uncurry converts a curried function to a function on pairs.
All it does is it takes a function (a -> b -> c) and returns a function that takes the parameters as a tuple.
So phy does the same thing as $, but instead of f $ x or ($) f x you call it like phy (f, x).
The other two answers are fine. I just have a slightly different take on it.
uncurry :: (a -> b -> c) -> (a, b) -> c
($) :: (a -> b) -> a -> b
Since the "->" in type signatures associates to the right, I can equivalently write these two type signatures like this:
uncurry :: (a -> b -> c) -> ((a, b) -> c)
($) :: (a -> b) -> (a -> b)
uncurry takes an arbitrary function of two inputs and changes it into a funciton of one argument where that argument is a tuple of the original two arguments.
($) takes a simple one-argument function and turns it into...itself. Its only effect is syntactical. f $ is equivalent to f.
(Make sure you understand higher-order functions and currying, read Learn You a Haskell chapter on higher-order functions, then read difference between . (dot) and $ (dollar sign) and function composition (.) and function application ($) idioms)
($) is just a function application, f $ x is equivalent to f x. But that's good, because we can use explicit function application, for example:
map ($2) $ map ($3) [(+), (-), (*), (**)] -- returns [5.0,1.0,6.0,9.0]
which is equivalent to:
map (($2) . ($3)) [(+), (-), (*), (**)] -- returns [5.0,1.0,6.0,9.0]
Check the type of ($): ($) :: (a -> b) -> a -> b. You know that type declarations are right-associative, therfore the type of ($) can also be written as (a -> b) -> (a -> b). Wait a second, what's that? A function that receives an unary function and returns an unary function of the same type? This looks like a particular version of an identity function id :: a -> a. Ok, some types first:
($) :: (a -> b) -> a -> b
id :: a -> a
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry ($) :: (b -> c, b) -> c
uncurry id :: (b -> c, b) -> c
When coding Haskell, always look at types, they give you lots of information before you even look at the code. So, what's a ($)? It's a function of 2 arguments. What's an uncurry? It's a function of 2 arguments too, the first being a function of 2 arguments. So uncurry ($) should typecheck, because 1st argument of uncurry should be a function of 2 arguments, which ($) is. Now try to guess the type of uncurry ($). If ($)'s type is (a -> b) -> a -> b, substitute it for (a -> b -> c): a becomes (a -> b), b becomes a, c becomes b, therefore, uncurry ($) returns a function of type ((a -> b), a) -> b. Or (b -> c, b) -> c as above, which is the same thing. So what does that type tells us? uncurry ($) accepts a tuple (function, value). Now try to guess what's it do from the type alone.
Now, before the answer, an interlude. Haskell is so strongly typed, that it forbids to return a value of a concrete type, if the type declaration has a type variable as a return value type. So if you have a function with a type a -> b, you can't return String. This makes sense, because if your function's type was a -> a and you always returned String, how would user be able to pass a value of any other type? You should either have a type String -> String or have a type a -> a and return a value that depends solely on an input variable. But this restriction also means that it is impossible to write a function for certain types. There is no function with type a -> b, because no one knows, what concrete type should be instead of b. Or [a] -> a, you know that this function can't be total, because user can pass an empty list, and what would the function return in that case? Type a should depend on a type inside the list, but the list has no “inside”, its empty, so you don't know what is the type of elements inside empty list. This restriction allows only for a very narrow elbow room for possible functions under a certain type, and this is why you get so much information about a function's possible behavior just by reading the type.
uncurry ($) returns something of type c, but it's a type variable, not a concrete type, so its value depends on something that is also of type c. And we see from type declaration that the function in the tuple returns values of type c. And the same function asks for a value of type b, which can only be found in the same tuple. There are no concrete types nor typeclasses, so the only thing uncurry ($) can do is to take the snd of a tuple, put it as an argument in function in fst of a tuple, return whatever it returns:
uncurry ($) ((+2), 2) -- 4
uncurry ($) (head, [1,2,3]) -- 1
uncurry ($) (map (+1), [1,2,3]) -- [2,3,4]
There is a cute program djinn that generates Haskell programs based on types. Play with it to see that our type guesses of uncurry ($)'s functionality is correct:
Djinn> f ? a -> a
f :: a -> a
f a = a
Djinn> f ? a -> b
-- f cannot be realized.
Djinn> f ? (b -> c, b) -> c
f :: (b -> c, b) -> c
f (a, b) = a b
This shows, also, that fst and snd are the only functions that can have their respective types:
Djinn> f ? (a, b) -> a
f :: (a, b) -> a
f (a, _) = a
Djinn> f ? (a, b) -> b
f :: (a, b) -> b
f (_, a) = a
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 ($).