Introduction To Haskell - All You Need To Know About Functions In Haskell

in technology •  7 years ago  (edited)

Welcome everyone, again I'm doing my series about Haskell. Yes you've read it right. I won't do the proves for now. Maybe later, but I'll focus more on Haskell now.
And sorry guys that I haven't been posting about it for too long. I hope you guys will be enjoying this still. 

PLEASE LET ME KNOW IF YOU WOULD LIKE THE TUTORIALS ALSO AS A VIDEO OR ONLY AS VIDEO WITH SHORT DESCRIPTIONS, OR WOULD YOU LIKE 'PROGRAM WITH ME' VIDEOS? I would really appreciate a comment about how you feel about this since I'm doing this for you guys.


Today I'll be covering more theory of Haskell and next time we'll program together some cool stuff like QUICK SORT. I restructured the tutorial series and will be focussing more on programming with you guys. 

Let's go no directly to the post.

Overview

  • higher-order functions
    • functions as arguments
    • functions as results
  • Lambda expressions
  • Function composition

Higher-order functions

In Haskell, functions can be arguments as well. This results to the definitions of first-order, second-order,... and higher-order functions.

Examples explain everything:

First-order:

Arguments are base types or constructor types . The typing looks like this then. (Example of function taking Int as an argument and having a list of Int as a result.

Int -> [Int] 

Second-order

Arguments can be themselves functions. The typing looks like this then. (Example of function taking a function of type Int->Int (taking Int as argument having Int as result type) and having the result [Int] )

(Int -> Int) -> [Int]

Third-order:

Arguments may be functions, whose arguments are functions. Let's explain the typing here again. This is a function with result type [Int] that takes a function of type ((Int -> Int) -> Int) as an argument. This itself is a function with result type Int and argument of type (Int -> Int) which itself is a function of first order-type.

((Int -> Int) -> Int) -> [Int]

Higher-order:

Let's generalize this:
Higher-order functions are functions that take functions as arguments. (Functions of arbitrary order).

Let's have a comparison to mathematics. Let's say we want to define a function 'f(x,y)' so that f(x,y) = x(y). Then that's second order.

Let's look at higher-order function map

map is a great Haskell function, that applies a function to every element of a list. So if you want to multiply every element of a list by two, you could give the function (2*) as the first argument and your list as the second argument.

Definition of map:

map :: (a -> b) -> [a] -> [b]
map f [] = []                    -- higher order
map f (x:xs) = f x : map f xs    -- (function f is an argument) 

Let's say we have the function (2*) and the list [1,2,3]. Then the result would be [2,4,5].

Of course you could do for example a mapping from integers to characters. Let's assume we would have defined a function that takes a integer i and gives as result the i-th letter in the alphabet. Then map function [1,2,3] would become [a,b,c].

Why the hell should I use this? What are the advantages of this?

  • Definition is easier to understand
  • Parts are easier to modify
  • Parts are easier to reuse
  • Correctness is simpler to understand and show

Exercise:

Look at the function foldr. You can find the definition online. Can you find out what it is doing? Can you understand why it is higher-order and why it's usefull? Comment your questions or tell us how easy this is for you.

Lambda expressions

more like '????????'

This is the lambda symbol by the way. 

Consider the following functions

times2 x = 2 * x                                    atEnd x xs = xs ++ [x]
double xs = map times2 xs                           rv xs = foldr atEnd [] xs

Haskell provides notation to write functions like times2 and atEnd in-line, which means that we don't have to define every single function with a name.
double xs would then look like this:

double xs = map (\x -> 2 * x) xs

And rev xs would be defined like this:

rev xs = foldr (\x xs -> xs ++ [x]) [] xs

The \ is the sign for 'lambda' in Haskell. As we see lambda expressions are actually a cool thing and very important.

Here are some calculations with the functions, so you can see what they do.

Usefull: function composition

You know maybe about function composition in math. In Haskell you can pretty much do the same.
In math function composition is the function f ◦ g. This means 'both are applied'. First g then f. So it's equal to f(g(x)).

In Haskell we can't use this circle, so we use the dot.       '.'   this symbol here.

The operator is defined as follows:

(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)   

 As you see, it's a function that takes a function of type (b -> c) and another one of type (a -> b) and the result is also a function which has type (a -> c). It obviously must be a function as a result since that is what the composition achieves.

What you can read from that type definition already. The resulting function takes an argument of type 'a', so the first function applied to this input will be the second one in order. And this is what results in the definition: g is the second argument in order and will be applied first.

times2 x = 2 * x
times3 x = 3 * x
example (whole evaluation)
(times2 . times3) 5 = times2 (times3 5) = times2 15 = 30


Alright guys, I hope you enjoyed reading this and came so far. If you did I would appreciate an upvote. I'll be posting soon the 'Program with me' post about functions which will contain just a little bit of theory and MOSTLY PROGRAMMING cool stuff. See you soon.

The face you realize it.

Cheers

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!