Haskell: The Purely Functional Programming Language
Haskell, an open source programming language, is the outcome of 20 years of research. Named after the logician, Haskell Curry, it has all the advantages of functional programming and an intuitive syntax based on mathematical notation. This second article
the function sumInt to compute the sum of two integers. It is defined as: sumInt :: Int -> Int -> Int sumInt x y = x + y
The first line is the type signature in which the function name, arguments and return types are separated using a double colon (::). The arguments and the return types are separated by the symbol (->). Thus, the above type signature tells us that the sum function takes two arguments of type Int and returns an Int. Note that the function names must always begin with the letters of the alphabet in lower case. The names are usually written in CamelCase style.
You can create a Sum.hs Haskell source file using your favourite text editor, and load the file on to the Glasgow Haskell Compiler interpreter (GHCi) using the following code: $ ghci GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Prelude> :l Sum.hs [1 of 1] Compiling Main Ok, modules loaded: Main.
( Sum.hs, interpreted ) *Main> :t sumInt sumInt :: Int -> Int -> Int *Main> sumInt 2 3 5
If we check the type of sumInt with arguments, we get the following output: *Main> :t sumInt 2 3 sumInt 2 3 :: Int
*Main> :t sumInt 2 sumInt 2 :: Int -> Int
The value of sumInt 2 3 is an Int as defined in the type signature. We can also partially apply the function sumInt with one argument and its return type will be Int -> Int. In other words, sumInt 2 takes an integer and will return an integer with 2 added to it.
Every function in Haskell takes only one argument. So, we can think of the sumInt function as one that takes an argument and returns a function that takes another argument and computes their sum. This return function can be defined as a sumTwoInt function that adds a 2 to an Int using the sumInt function, as shown below: sumTwoInt :: Int -> Int sumTwoInt x = sumInt 2 x
The ‘=’ sign in Haskell signifies a definition and not a variable assignment as seen in imperative programming languages. We can thus omit the ‘x' on either side and the code becomes even more concise: sumTwoInt :: Int -> Int sumTwoInt = sumInt 2
By loading Sum.hs again in the GHCi prompt, we get the following: *Main> :l Sum.hs [1 of 1] Compiling Main Ok, modules loaded: Main.
( Sum.hs, interpreted ) *Main> :t sumTwoInt sumTwoInt :: Int -> Int *Main> sumTwoInt 3 5
Let us look at some examples of functions that operate on lists. Consider list ‘ a', which is defined as [ 1, 2, 3, 4, 5] ( a list of integers) in the Sum.hs file (re-load the file in GHCi before trying the list functions). a :: [Int] a = [1, 2, 3, 4, 5]
The head function returns the first element of a list: *Main> head a 1 *Main> :t head head :: [a] -> a
The tail function returns everything except the first element
from a list: *Main> tail a [2,3,4,5] *Main> :t tail tail :: [a] -> [a]
The last function returns the last element of a list: *Main> last a 5 *Main> :t last last :: [a] -> a
The init function returns everything except the last element of a list: *Main> init a [1,2,3,4] *Main> :t init init :: [a] -> [a]
The length function returns the length of a list: *Main> length a 5 *Main> :t length length :: [a] -> Int
The take function picks the first ‘n' elements from a list: *Main> take 3 a [1,2,3] *Main> :t take take :: Int -> [a] -> [a]
The drop function drops ‘n' elements from the beginning of a list, and returns the rest: *Main> drop 3 a [4,5] *Main> :t drop drop :: Int -> [a] -> [a]
The zip function takes two lists and creates a new list of tuples with the respective pairs from each list. For example:
*Main> let b = ["one", "two", "three", "four", "five"]
*Main> zip a b [(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five")] *Main> :t zip zip :: [a] -> [b] -> [(a, b)]
The let expression defines the value of ‘b' in the GHCi prompt. You can also define it in a way that’s similar to the definition of the list ‘a' in the source file.
The lines function takes input text and splits it at new lines:
*Main> let sentence = "First\nSecond\nThird\nFourth\nFifth" *Main> lines sentence ["First","Second","Third","Fourth","Fifth"] *Main> :t lines lines :: String -> [String]
The words function takes input text and splits it on white space: *Main> words "hello world" ["hello","world"] *Main> :t words words :: String -> [String]
The map function takes a function and a list, and applies the function to every element in the list: *Main> map sumTwoInt a [3,4,5,6,7] *Main> :t map map :: (a -> b) -> [a] -> [b]
The first argument to map is a function that is enclosed within parenthesis in the type signature (a -> b). This function takes an input of type ‘a' and returns an element of type ‘b'. Thus, when operating over a list [a], it returns a list of type [b].
Recursion provides a means of looping in functional programming languages. The factorial of a number, for example, can be computed in Haskell, using the following code: factorial :: Int -> Int factorial 0 = 1 factorial n = n * factorial (n-1)
The definition of factorial with different input use cases is called pattern matching on the function. On running the above example with GHCi, you get the following output:
*Main> factorial 0 1 *Main> factorial 1 1 *Main> factorial 2 2 *Main> factorial 3 6 *Main> factorial 4 24 *Main> factorial 5 120
Functions operating on lists can also be called recursively. To compute the sum of a list of integers, you can write the sumList function as: sumList :: [Int] -> Int sumList  = 0 sumList (x:xs) = x + sumList xs
The notation (x:xs) represents a list, where ‘x' is the first element in the list and ‘xs' is the rest of the list. On running sumList with GHCi, you get the following: *Main> sumList  0 *Main> sumList [1,2,3] 6
Sometimes, you will need a temporary function for a computation, which you will not need to use elsewhere. You can then write an anonymous function. A function to increment an input value can be defined as: *Main> (\x -> x + 1) 3 4
These are called Lambda functions, and the '\' represents the notation for the symbol Lambda. Another example is given below: *Main> map (\x -> x * x) [1, 2, 3, 4, 5] [1,4,9,16,25]
It is a good practice to write the type signature of the function first when composing programs, and then write the body of the function. Haskell is a functional programming language and understanding the use of functions is very important.