Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why sum x y is of type (Num a) => a -> a -> a in Haskell?

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?
like image 741
devoured elysium Avatar asked Sep 18 '10 17:09

devoured elysium


People also ask

What is -> in Haskell?

(->) is often called the "function arrow" or "function type constructor", and while it does have some special syntax, there's not that much special about it. It's essentially an infix type operator. Give it two types, and it gives you the type of functions between those types.

What does A -> B mean in Haskell?

a -> b Bool means... forall (a :: *) (b :: * -> *). a -> b Bool. b is therefore a type constructor taking a single type argument. Examples of single-argument type constructors abound: Maybe , [] , IO are all examples of things which you could use to instantiate b .

What are types in Haskell?

In Haskell, every statement is considered as a mathematical expression and the category of this expression is called as a Type. You can say that "Type" is the data type of the expression used at compile time. To learn more about the Type, we will use the ":t" command.

How types are declared in Haskell?

Haskell has three basic ways to declare a new type: The data declaration, which defines new data types. The type declaration for type synonyms, that is, alternative names for existing types. The newtype declaration, which defines new data types equivalent to existing ones.


2 Answers

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, or more specifically, an interface base-type constraint in generics. 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) 
like image 190
kennytm Avatar answered Oct 12 '22 22:10

kennytm


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.

like image 34
Lie Ryan Avatar answered Oct 13 '22 00:10

Lie Ryan