Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
For example:
f :: (b -> c) -> (a -> b) -> c
g h
he function f takes two functions (lets call them g and h) as input-arguments, and returns a value of type c
First argument: (a -> b)
Second argument: (b -> c)
Returns: a value of type c
In order for this function definition to be true the types have to line up, like this: (a -> b) -> (b -> c) <=equivalent to=> a -> c
and the only way for this to work is if the second argument is used as input for the first argument, like this g(h(x)), where x is of type a, is this true for all functions in Haskell? In other words
is the right argument always going to be defined as the input for its left argument? And is this the general case for all composed functions in Haskell?
And if so should I always read and interpret function-arguments from right to left instead of left to right?
OBS:
This question is not the same question as:
Why does the dot compose from right to left in haskell
Because my question is more general for all functions, also I already know that a function composed of other functions is called function compositon, and I know about the dot-function etc.
I think you might be confusing things a little. In your example, replicated below:
f :: (b -> c) -> (a -> b) -> c
Here f is a higher order function, which means that it can take other functions as parameters. As a matter of fact, its first parameter is a function of type (b -> c). Its second argument is a function of type (a -> b).
The parameters of a function do not have to be related to each other at all. In your case, it was simply a coincidence. We could have easily done something like this:
g :: (Int -> Double) -> (Char -> Bool) -> String
g func1 func2 = "three"
Another thing to be aware of is that all functions in Haskell are curried. Think back to a language like C:
char foo (int a, double b) { ... }
The function takes (int, double) and returns a char. We might even write its type signature like this:
(int, double) -> char
In Haskell, we don't require all parameters to be fed in at once, and it is expressed as this:
int -> double -> char
Why in the world would you want this? Consider the following scenario:
add :: Int -> Int -> Int
add a b = a + b
Check this out:
addFive :: Int -> Int
addFive = add 5
Applying less arguments than the function's parameter requires allows you to create new functions that are somewhat "customized". Pretty cool, huh? :)
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 months ago.
Improve this question
I have been asked to give an example of a function defined as (Int->Int)->Int in Haskell. No matter how simple.
(Int -> Int) -> Int is a function of one argument. The type of the argument is Int -> Int, and the return type is Int
The argument has type Int -> Int, which means that it's also a function of one argument. This function's argument is of type Int and its return type is Int
The simplest example would be probably this:
f :: (Int -> Int) -> Int
f g = g 42
As explained, (Int -> Int) -> Int is the type of a function producing an Int from another function, which in turns produces an Int from an Int.
How simple can such a function be?
Think about it:
you want to generate an Int
but the only argument you can use to do so is a function Int -> Int, for which you are not given an input!
So you either
ignore that input function entirely and choose a result for your function, e.g. 6
f :: (Int -> Int) -> Int
f _ = 6 -- _ means that I don't even bother
-- giving a name to the argument,
-- as I don't use it
So f simply ignores its only argument and always gives you back 6. Now look at const's description and examples. Oh, but that gives us a way to implement f,
f :: (Int -> Int) -> Int
f = const 6
which also gives us the chance to choose a more appropriate name for f: always6.
or choose a fixed argument for it (as suggested in the other answer), e.g. 6
f :: (Int -> Int) -> Int
f g = g 6
Here f takes g and applies it to 6, no matter what. A better name for this f function would be maybe applyTo6.
something :: a -> (a -> ())
Is there a name/concept for something, the function that takes an a and returns a function from a to unit?
That is given an a, it returns a sink/consumer of a?
Is something just a -> a -> (), a bi-consumer of a?
.
What about:
somethingElse :: a -> (a -> a)
the function from a to a function from a to a?
somethingElse is basically a combiner or binary operator on a, a -> a -> a, right?
All possible implementations of something are equivalent to
sink :: a -> a -> ()
sink x y = ()
which you could also write as
sink = const $ const ()
As you can imagine, this is not a very frequently used function (it is guaranteed to never do anything interesting), and so there is no special name for it.
Your second question, about a -> a -> a, is more interesting. If the function is to be polymorphic, i.e. to work over any a at all, there are just two possible implementations:
first x y = x
second x y = y
But this type can be specialized to do something interesting for more specific a types.
(+) :: Int -> Int -> Int
is one example of such a specialization. Indeed this is the type of a binary operator, and any binary operator taking and returning a values has this type, or a specialization of it.
Functions of this type are related to Monoid and to Semigroup, in a way, but not all such functions meet the rules necessary to be part of a Monoid or Semigroup instance.
I'm still a beginner when it comes to Haskell syntax and functional programming languages so when I look at the type declaration for Data.Function.on which is on :: (b -> b -> c) -> (a -> b) -> a -> a -> c, my interpretation is that it takes four parameters: (b -> b -> c), (a -> b), a, a, and returns c. However, when I look at the general use syntax for Data.Function.on which is (*) `on` f = \x y -> f x * f y, it is only taking two function parameters, not four, so how does the type signature relate to the usage syntax?
my interpretation is that it takes four parameters
All Haskell functions take one argument. Some of them just return other functions.
The best way to look at the signature for on is as a higher-order function: (b -> b -> c) -> (a -> b) -> (a -> a -> c). This says "if you give me a binary operator that takes bs and gives a c and a way to get bs from as, I will give you a binary operator that takes as and gives a c". You can see this in the definition:
(*) `on` f = \x y -> f x * f y
The Haskell arrow for function types hides a simple but clever idea. You have to think of -> as an operator, like + and -, but for types. It takes two types as arguments and gives you a new type consisting of a function. So in
Int -> String
You have the types Int and String, and you get a function from an Int to a String.
Just like any other operator, you need a rule for a chain of them. If you think of -, what does this mean?
10 - 6 - 4
Does it mean (10 - 6) - 4 = 0, or does it mean 10 - (6 - 4) = 8? The answer is the first one, which is why we say that - is "left associative".
The -> operator is right associative, so
foo :: Int -> String -> String
actually means
foo :: Int -> (String -> String)
Think about what this means. It means that foo doesn't take 2 arguments and return a result of type String, it actually takes 1 argument (the Int) and returns a new function that takes the second argument (the String) and returns the final String.
Function application works the same way, except that is left associative. So
foo 15 "wibble"
actually means
(foo 15) "wibble"
So foo is applied to 15 and returns a new function which is then applied to "wibble".
This leads to a neat trick: instead of having to provide all the parameters when you call a function (as you do in just about every other programming language), you can just provide the first one or the first few, and get back a new function that expects the rest of the parameters.
This is what is happening with on. I'll use a more concrete version where 'f' is replaced by 'length'.
(*) on length
you give on its first two parameters. The result is a new function that expects the other two. In types,
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
In this case (*) has type Num n => n -> n -> n (I'm using different letters to make this less confusing), so that is matched with the type of the first argument to on, leading to the conclusion that if type b is substitued by n then type c must be as well, and and must also be a Num instance. Therefore length must return some numeric type. As it happens the type of length is [d] -> Int, and Int is an instance of Num, so that works out. So at the end of this you get:
(*) `on` length :: [d] -> [d] -> Int
As an intuitive aid, I read this as "if you give me a comparator of type b, and a way to extract values of type b from values of type a, I will give you a comparator of type a".
E.g. if a is some composite data type and b is some numerical attribute of these data values, you can express the idea of sorting these composite data types by using Data.Function.on.
Reading http://www.seas.upenn.edu/~cis194/spring13/lectures/04-higher-order.html it states
In particular, note that function arrows associate to the right, that
is, W -> X -> Y -> Z is equivalent to W -> (X -> (Y -> Z)). We can
always add or remove parentheses around the rightmost top-level arrow
in a type.
Function arrows associate to the right but as function application associates to the left then what is usefulness of this information ? I feel I'm not understanding something as to me it is a meaningless point that function arrows associate to the right. As function application always associates to the left then this the only associativity I should be concerned with ?
Function arrows associate to the right but [...] what is usefulness of this information?
If you see a type signature like, for example, f : String -> Int -> Bool you need to know the associativity of the function arrow to understand what the type of f really is:
if the arrow associates to the left, then the type means (String -> Int) -> Bool, that is, f takes a function as argument and returns a boolean.
if the arrow associates to the right, then the type means String -> (Int -> Bool), that is, f takes a string as argument and returns a function.
That's a big difference, and if you want to use f, you need to know which one it is. Since the function arrow associates to the right, you know that it has to be the second option: f takes a string and returns a function.
Function arrows associate to the right [...] function application associates to the left
These two choices work well together. For example, we can call the f from above as f "answer" 42 which really means (f "answer") 42. So we are passing the string "answer" to f which returns a function. And then we're passing the number 42 to that function, which returns a boolean. In effect, we're almost using f as a function with two arguments.
This is the standard way of writing functions with two (or more) arguments in Haskell, so it is a very common use case. Because of the associativity of function application and of the function arrow, we can write this common use case without parentheses.
When defining a two-argument curried function, we usually write something like this:
f :: a -> b -> c
f x y = ...
If the arrow did not associate to the right, the above type would instead have to be spelled out as a -> (b -> c). So the usefulness of ->'s associativity is that it saves us from writing too many parentheses when declaring function types.
If an operator # is 'right associative', it means this:
a # b # c # d = a # (b # (c # d))
... for any number of arguments. It behaves like foldr
This means that:
a -> b -> c -> d = a -> (b -> (c -> d))
Note: a -> (b -> (c -> d)) =/= ((a -> b) -> c) -> d ! This is very important.
What this tells us is that, say, foldr:
λ> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
Takes a function of type (a -> b -> b), and then returns... a function that takes a b, and then returns... a function that takes a [a], and then returns... a b. This means that we can apply functions like this
f a b c
because
f a b c = ((f a) b) c
and f will return two functions each time an argument is given.
Essentially, this isn't very useful as such, but is important information for when we want to interpret and call function types.
However, in functions like (++), associativity matters. If (++) were left associative, it would be very slow, so it's right associative.
Early functional language Lisp suffered from excessively nested parenthesis (which make code (or even text (if you do not mind to consider a broader context)) difficult to read. With time functional language designers opted to make functional code easy to read and write for pros even at cost of confusing rookies with less uniform rules.
In functional code,
function type declaration like (String -> Int) -> Bool are much more rare than functions like String -> (Int -> Bool), because functions that return functions are trade mark of functional style. Thus associating arrows to right helps reduce parentheses number (on overage, you might need to map a function to a primitive type). For function applications it is vise-versa.
The main purposes is convenience, because partial function application goes from left to right.
Every time you partially apply a function to a set of values, the remaining type has to be valid.
You can think of arrow types as a queue of types, where the queue itself is a type. During partial function application, you dequeue as many types from the queue as the number of arguments, yielding whatever remains of the queue. The resulting queue is still a valid type.
This is why types associate to the right. If types associate to the left, it will behave like a stack, and you won't be able to partially apply it the same way without leaving "holes" or undefined domains. For instance, say you have the following function:
foo :: a -> b -> c -> d
If Haskell types were left-associative, then passing a single parameter to foo would yield the following invalid type:
((? -> b) -> c) -> d
You will then be forced to circumvent it by adding parentheses, which could hamper readability.
I'm having some trouble understanding, how this type declaration works.
The type is: (a -> b) -> (b -> c) -> (c -> d) -> a -> d
So, to me I interpret this as a function that takes a function and that function takes another function which outputs a value d.
So, this is how I make my function:
Example :: (a -> b) -> (b -> c) -> (c -> d) -> a -> d
Example f g h x = f ( g ( h (x) )
I'd really appreciate it, if you guys could help me clarify. Thank you!
I think that you already know the theory behind the type you're writing, so I'll try to inject some intuitive way to read it (at least I hope so, your question is not totally clear to me).
When you read something like (a -> b) inside a type, that's a function, as you said. For example (Int -> Bool) is a function.
Let's make an example:
even :: Int -> Bool -- A more generic version of that is in the Prelude
even n = n `rem` 2 == 0
filter :: (Int -> Bool) -> [Int] -> [Int] -- And of that, too
filter _ [] = []
filter f (x:xs)
| f x = x : filter f xs
| otherwise = filter f xs
filteredEven :: [Int]
filteredEven = filter even [1..5] -- it gives [2, 4]
In this example we have a "high order function", a function that get another function and use it in some way.
In a function like the one you're defining you simply use 3 functions (and another parameter). But you can know more.
Each function you declare in the type accept a value returned from the previous one. So a possible solution is the one you have already showed. But the types are generic. There is not a total function that returns a generic value (where total means that it terminate always returning a value different from bottom if all the values are total and different by bottom, so it don't crash or return undefined, for example). So, if you wants a total function you have to have a way to generate the variables requested, from the context of the function (their parameters).
In the example before, using the names used by you, you have to return a value of type d. You only have a way to produce a value of that type, the h function. But to use the h function you have to get a value of type c. You only have the g function for that. But you need a value of type c. Fortunately you have the function f, that in exchange of a value of type a returns the value needed. We have this value (and don't have any other way to obtain a value of that type), so the function can be written. We can't in any way alter the values obtained (call multiple times the functions don't work, for purity and the fact that we have only a way to produce the values), so that's the only way to construct the function, if we wants it to be total:
Example (a -> b) -> (b -> c) -> (c -> d) -> a -> d
Example f g h x = h (g (f x)))
We can write the function in many other ways, but the results they give will be always the same (if Example, f, g and h are total and x is not bottom). So the type can express really well the function, because we can understand how the function works only looking at the type!