Haskell is a strongly typed static language.
This means that Haskell will not automatically cast one type into another. In other words, you can’t expect it to treat an integer as a float. If you define a function that takes a float parameter and you feed it an integer afterwards, Haskell will complain. Having static types means that the compiler knows the type of every value and expression at compile time. Before anything is executed. So if we try and use types in an expression that don’t match (say, trying to add a string “3” to an integer 5), Haskell will complain. But there is a bonus: Haskell has type inference. Meaning, Haskell will deduce the type of a value or expression for us everywhere it can. This makes type declaration optional.
Continuing my journey into the abyss of Haskell, it occured to me that we all already learned functional programming. Do you still remember the basic Algebra classes in your elementary school? Well, that is just it - functional programming. And Haskell’s syntax is just like algebra. With some extra sugar and batteries included (yes, i took that last part from Python … i just couldn’t resist).
At the algebra classes we learned that functions return values. Later we were spoiled by imperative programming languages and the returning values became an option explicitly stated with return keyword. Not in Haskell. All functions return values, because they are expressions. Always. And we don’t need the return anymore because we get it implicitly. Oh, and did I tell you that there are no objects in Haskell? Just functions!
To define a function that returns a sum of two numbers I could write something like the following:
add a b = a + b
Here I tell Haskell that add takes two parameters and it should return a sum of the two. I didn’t have to declare the types of the parameters, nor the returned value. And i could have, if I weren’t so lazy! But I am safe anyway. If i try to pass two strings to the function, Haskell will yell at me. That’s inference at work.
Let’s say that i want to be a good citizen and declare the types as well, but being new to Haskell i just am not really sure what they could be. Well, I can always check it out after I write my function down with the help of the interpreter.
ghci> :t add
ghci> add :: (Num a) => a -> a -> a
Haskell is telling us that for him, the add function can take any two parameters that are of the same type and it will return a value of the same type back, but the type must be of a Number typeclass. Ok, I had some hard time to decipher it as well, so let me rephrase this a little bit. The (Num a) part is telling us that for all the “a”s that follow they must be of a numeric type. The part “a->a->a” is simplified like this: the last a is the return value, while the first two are function arguments. So, armed with this insight i can go back and modify my function so that it has a type declaration as well.
add :: (Num a) => a -> a -> a
add a b = a + b
Yes, it is weird at first. But quite soon it starts to make sense, trust me. And wait till next week when i show you patterns and guards!