0

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.

August Jelemson
  • 962
  • 1
  • 10
  • 29
  • The second argument *is not per se* called. If the first argument is for instance `const False`, then Haskell does not care about the second function or the input at all. – Willem Van Onsem Jun 26 '17 at 18:54
  • Willem Van Onsem, I understand that but my question is really: How to interpret functions in Haskell, from my experience so far, I have to read input-arguments from right to left in order for them to make sence – August Jelemson Jun 26 '17 at 18:56
  • 1
    Did you mix up the order of arguments in your type signature vs. the line below it? If the type signature is `(b -> c) -> (a -> b) -> c`, then the first argument would have type `b -> c`, not `a -> b`. Beyond that I have a hard time understanding what you're asking. – sepp2k Jun 26 '17 at 18:58
  • sepp2k, no I did not make a mistake, because in Haskell my type signature would actually work, and the only way it would work is if a -> b -> b -> c is true – August Jelemson Jun 26 '17 at 19:01
  • 1
    @AugustJelemson No, there are absolutely no restrictions on function types. There's nothing that stops you from writing a `g :: (a -> b) -> (b -> c) -> a -> c` function. There's nothing that even says that function parameters would need to be functions. It's just a convention to use infix function composition this way. – Bergi Jun 26 '17 at 19:04
  • @Bergi, is it because of type inference? – August Jelemson Jun 26 '17 at 19:06
  • 1
    I have no idea what you mean by "*for this function definition to be true the types have to line up*". – Bergi Jun 26 '17 at 19:06
  • Btw, you seem to be missing an `a` parameter somewhere in the signature of `f`. – Bergi Jun 26 '17 at 19:07
  • if the types line up we have: a -> b -> b -> c if they don't line up we have : b -> c -> a-> b – August Jelemson Jun 26 '17 at 19:07
  • @AugustJelemson what makes you think they have to line up that way? `f` could do anything with those function arguments and then return anything. You seem to be confusing higher order functions with function composition. – Jared Smith Jun 26 '17 at 19:09
  • @AugustJelemson yes, if you try to compose functions then the input and output types must line up. I (and apparently not just me) still don't understand what that has to do with what you wrote. If I use concrete instead of generic types and say `f :: (String -> Int) -> (Bool -> String) -> Int` then what I have is a 'function which takes a function from string to int and yields a function that takes a function from bool to string and yields and int. Which is invalid because...? – Jared Smith Jun 26 '17 at 19:18
  • I'd advice you to implement some of these [birds](https://hackage.haskell.org/package/data-aviary-0.4.0/docs/Data-Aviary-Birds.html) to get a better feel for type signatures and the corresponding combinator implementations. There are a lot of birds flying around, not only bluebirds. –  Jun 26 '17 at 20:18
  • 2
    This question has so many terminology mistakes and so much vagueness that it is very difficult to tell what you currently believe to be true; this makes it next to impossible to identify the mistake(s) in your current beliefs. I'm voting to close -- but I encourage you to try to crystallize your claims here to be more precise. The following phrases appear to be unexplained (and not using their standard meaning, where one exists): "first"/"second" argument, "function definition", a function definition that is "true", type equivalence, "composed functions", "read functions left to right". – Daniel Wagner Jun 26 '17 at 20:48
  • If I'm reading the question right the answer is: No, it's not fundamental that you "have to read arguments from right to left for functions to make sense", and you shouldn't try to read everything that way. The `.` operator could easily have been defined the other way around, we weren't *forced* to write it that way. It has the useful property that in `(f . g . h) x` the argument `x` "moves through" the functions in the same order as in ordinary application like `f (g (h x))`. But that's *just* function composition; many other functions do things differently (such as `>>=` for example). – Ben Jun 27 '17 at 01:24
  • I'm nominating this for reopening; it could certainly be worded *better*, but I think I understand what the OP's question is. They've seen some functions (like `(.) :: (b -> c) -> (a -> b) -> c`) that seem to make more sense to them when they consider the arguments in right-to-left order (so in `f . g`, thinking of `g` as the "first" argument of `(.)` and `f` as the second), and are wondering if that's a property of Haskell functions more generally. – Ben Jun 27 '17 at 01:30
  • @Ben, I disagree. I believe the OP will have a much better chance of resolving their confusion through other paths than this question, and I doubt that other users will find this question helpful. – dfeuer Jun 27 '17 at 03:35
  • It worries me that this question is closed, because that's will just make OP have a negative reaction about Haskell, which is really not what we want. A careful reading of the first few chapters of the tutorial I helped author would clear this up: http://happylearnhaskelltutorial.com – Julian Leviston Jun 27 '17 at 09:43
  • @JulianLeviston the question is closed because it does not meet the requirements of a stack overflow question, numerous people asked for but didn't get clarification from the OP, etc. Haskell is not the issue, although you're right that it doesn't make for good marketing that very issue has been beaten to death on meta. – Jared Smith Jun 27 '17 at 12:31
  • @JaredSmith it's nothing to do with *marketing* and everything to do with helping someone and others that are looking for similar answers, but don't necessarily have the skills to ask the right quesiton, or in the right way. It's quite possible to answer this in a way that covers of all of the kinds of questions it could possibly mean while educating this person as well as others like the OP. – Julian Leviston Jun 27 '17 at 12:50
  • @JulianLeviston I applaud your devotion to helping others. And don't disparage marketing, presenting a good face is not inherently *bad*. As for not having the skills to ask the right question, that's pretty common, and thus the requests for feedback (which were unfortunately ignored). – Jared Smith Jun 27 '17 at 13:27
  • @JaredSmith fair enough... personally I've been in similarly flummoxed places. I just wish I could write the answer I wish I could have had when in the OP's situation... which steps me through from nothing what's missing... because it's obvious that something's missing, but OP is probably finding it tricky threading through what's missing. All good, though. Hopefully they'll stick with it like I did. – Julian Leviston Jun 27 '17 at 22:40

1 Answers1

6

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? :)

Anton Xue
  • 813
  • 11
  • 25