views:

294

answers:

5

I've been reading about Haskell and I'm having a hard time understanding how function definitions are handled in this language.

Let's say I'm defining a sum function:

let sum x y = x + y

if I query Haskell for its type

:t sum

I get

sum :: (Num a) => a -> a -> a
  1. What does it mean the => operator? Does it have anything to do with lambda expressions? That's how one signals that what is following the => operator is one, in C#.
  2. What does the a -> a -> a mean? By eye inspection on a number of different functions I've been trying out, it seems the initial a -> a are the arguments and the final -> a is the result of the sum function. If that is right, why not something as (a, a) -> a, which seems way more intuitive?
+3  A: 

it is a -> a -> a rather than (a, a) -> a because of currying. Fun fact: Currying was (re)invented by Haskell Curry! Basically it means if you supply one one argument you'll get back another function of type a -> a, a partial application of sum.

fredley
Even after reading the intro to the Wikipedia article, I can't get what is the point of currying :(
devoured elysium
I don't get the point either! It's just one of those things you *do* in functional programming...
fredley
You curry functions so you can partially apply them. Want to add 3 to every element in a list? No problem! - map (+3) [1, 2, 3, 4, 5]
Paul
@Paul Harvey: Actually, `map (+3)` is bad example of partial application, it really is an. operator section. `map ((+) 3)` is partial application.
Matajon
If you have function "sendMessage to type content" and you often send numberic status messages to "server", you could create helper function with partial application: "sendStatus = sendMessage server number" and use it like "sendStatus 10".
ADEpt
@Matajon: In Haskell the partial application of an infix operator is called a section, yes. It's still partial application however.
Paul
Another way to think about it: what does 'plus 1' return? A fully-featured function of its own which binds one of the inputs to 1. The ability to trivially generate new functions from existing ones, even whole families of new functions, through elementary operations like partial application, is the point.
Owen S.
+4  A: 

Num a => means "in the following, a shall refer to a type which is an instance of the typeclass Num" (which is kinda like an interface for number types).

The => operator separates the "typeclass constraints" from the "body" of the type. It's kind of like the where operator for generic constraints in C#. You can read it as a logical implication like "if a is a numeric type then sum can be used with type a -> a -> a".

a -> a -> a means "a function that takes an a and returns a function which takes an a and returns an a". For this to make sense you need to understand that sum x y parses as (sum x) y.

In other words: you first call sum with the argument x. You then get back a new function of type a -> a. You then call that function with the argument y and now you get back a function of type a, where a is the type of x and y and must be an instance of the Num typeclass.

If you want sum to have type Num a => (a,a) -> a, you can define it as sum (x,y) = x+y. In this case you have a function which takes a tuple containing two as and returns an a (where a is again an instance of the Num typeclass).

However the "curry style" (functions returning functions to simulate multiple parameters) is much more often used than the tuple style because it allows you to easily partially apply functions. Example map (sum 5) [1,2,3]. If you had defined sum with a tuple, you'd have to do map (\y -> sum 5 y) [1,2,3].

sepp2k
+7  A: 

This is because

Every function in Haskell takes a single parameter and returns a single value

If a function need to take multiple value, the function would have been a curried function or it have to take a single tuple.

If we add a parentheses, the function signature becomes:

sum :: (Num a) => a -> (a -> a)

In Haskell, the function signature: A -> B means a function the "domain" of the function is A and the "Codomain" of the function is B; or in a programmer's language, the function takes a parameter of type A and returns a value of type B.

Therefore, the function definition sum :: Num -> (Num -> Num) means sum is "a function that takes a parameter of type a and returns a function of type Num -> Num".

In effect, this leads to currying/partial function.

The concept of currying is essential in functional languages like Haskell, because you will want to do things like:

map (sum 5) [1, 2, 3, 5, 3, 1, 3, 4]  -- note: it is usually better to use (+ 5)

In that code, (sum 5) is a function that takes a single parameter, this function (sum 5) will be called for each item in the list, e.g. ((sum 5) 1) returns 6.

If sum had a signature of sum :: (Num, Num) -> Num, then sum would have to receive both of its parameter at the same time because now sum is a "function that receives a tuple (Num, Num) and returns a Num".

Now, the second question, what does Num a => a -> a means? It's basically a shorthand for saying that each time you see a in the signature, replace it with Num or with one of its derived class.

Lie Ryan
You are abusing the notation a bit: `Num` is a typeclass, not a type.
Dave Hinton
+3  A: 

The Haskell documentation isn't too clear about it, but (Num a) => means that the function works for all cases where a is a Num or derives from it (therefore is a number).

Also see: http://www.cse.unsw.edu.au/~en1000/haskell/inbuilt.html

alper
+17  A: 

0. The Haskell => has nothing to do with C#'s =>. In Haskell an anonymous function is created with

\x -> x * x

Also, don't name the function sum because such a function already exists in Prelude. Let's call it plus from now on to avoid confusion.

1. Anyway, the => in Haskell provides a context to the type. For instance:

show :: (Show a) => a -> String

Here, The Show a => means a type must be an instance of the type class Show, which means a must be convertible to a string. Similarly, (Num a) => a -> a -> a means the a type must be an instance of the type class Num, which means a must be like a number. This puts a constraint on a so that show or plus won't accept some unsupported input, e.g. plus "56" "abc". (String is not like a number.)

A type class is similar to C#'s interface. See the question Explain Type Classes in Haskell for more info.

2. a -> a -> a means a -> (a -> a). Therefore, it is actually a unary function that returns another function.

plus x = \y -> x + y

This makes partial application (currying) very easy. Partial application is used a lot esp. when using higher order functions. For instance we could use

map (plus 4) [1,2,3,4]

to add 4 to every element of the list. In fact we could again use partial application to define:

plusFourToList :: Num a => [a] -> [a]
plusFourToList = map (plus 4)

If a function is written in the form (a,b,c,...)->z by default, we would have to introduce a lot of lambdas:

plusFourToList = \l -> map(\y -> plus(4,y), l) 
KennyTM
Good answer, except that I always cringe when I hear someone say that type classes are like interface classes. They have a somewhat analogous role, but reasoning from that analogy will lead you seriously astray. In particular in Haskell a type class is not itself a type, so you can't write "[Num]" to mean a list of numbers.
Paul Johnson
Though writing (Num a) => [a] is not really so different. I believe, so long as you make it clear that the interface analogy is just a simple one to help you get started, it is okay.
Robert Massaioli
Even if C# had a `Num` interface, something like `List<Num>` is still quite different from `(Num a) => [a]`, because `[5::Int, 3.5::Double]` is not a valid value of type `(Num a) => [a]` in Haskell. I think this surprises a lot of people when they first see type classes.
hzap