Interactive Haskell

This section will be used to familiarize you with the Haskell interactive command line. Before we introduce you to the interactive command line, we will introduce the optional configuration file that you can create in ~/.ghci in your home folder. We have configured ours with the following code:

:set prompt "> "

The preceding code tells the interactive command line to display a single > as the prompt. You can start the interactive command line using the ghci command. Here is what you will see when the command line is started:

$ ghci
GHCi, version 7.4.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
>

You can execute simple equations using either the familiar infix notation, or the functional notation:

> 2 + 2
4
> (+) 2 2
4
> 2 + 4 * 5
22
> (+) 2 $ (*) 4 5
22

Note that we need to use $ here in order to tell Haskell that the (*) 4 5 multiplication portion is an argument to the (+) 2 addition portion.

An introductory problem

This introductory problem will serve as a way of explaining the features of the Haskell language that are used repeatedly in this book. The problem is that we wish to know the location of the vowel characters of a given word, for example, in the word apple, there are two vowels (the first and fifth letters). Given a string apple, we should return a list of [1, 5]. We will go through the thought process of solving this problem and turn our solution into a function. You can use the elemIndices function that can be found in the Data.List module, but we will chose not to do so for teaching purposes.

First, we will declare a variable to store our word. In this example, we will use the word apple:

> let word = "apple"

We will assign a number to each letter in our word using zip and an infinite list of numbers. The zip function will perform a pair-wise merge of two lists to create a list of tuples. A tuple is a type of list structure that can store types in a heterogeneous manner. In the following code, we will combine the integer and character types:

> zip [1..] word
[(1,'a'),(2,'p'),(3,'p'),(4,'l'),(5,'e')]

The expression [1..] is an infinite list of numbers. If you type this in the interactive command line, numbers will appear until you decide to stop it. By using it in conjunction with zip, we only take what we need. There are five letters in apple. So, we only take five elements from our infinite list. This is an example of lazy evaluation at work.

Next, we will filter our list to remove anything that is not a vowel character. We will do this with the help of the filter function, which requires us to pass a lambda function with the rule that defines what is allowed in the list of values:

> filter ((_, letter) -> elem letter "aeiouAEIOU") $ zip [1..] word
[(1,'a'),(5,'e')]

Let's take a closer look at the lambda expression that is within the parentheses that begin with ( and end with ). Using the :t option, we can inspect how Haskell interprets this function:

> :t (_, letter) -> elem letter "aeiouAEIOU"
(_, letter) -> elem letter "aeiouAEIOU" :: (t, Char) -> Bool

The function requires a pair of values. The first value in the pair is identified with _, which indicates that this is a wild card type. You can see that Haskell identifies it with the t generic type. The second value in the pair is identified by letter, which represents a character in our string. We never defined that letter was a Char type, but Haskell was able to use type inference to realize that we were using the value in a list to search for the value among a list of characters and thus, this must be a character. This lambda expression calls the elem function, which is a part of the Data.List module. The elem function returns a Bool type. So, the return type of Bool is also inferred. The elem function returns true if a value exists in a list. Otherwise, it returns false.

We need to remove the letters from our list of values and return a list of only the numbers:

> map fst . filter ((_, letter) -> elem letter "aeiouAEIOU") $ zip [1..] word
[1,5]

The map function, like the filter, requires a function and a list. Here, the function is fst and the list is provided by the value returned by the call to the filter. Typically, tuples consist of two values (but this is not always the case). The fst and snd functions will extract the first and second values of a tuple, as follows:

> :t fst
fst :: (a, b) -> a
> :t snd
snd :: (a, b) -> b
> fst (1, 'a')
1
> snd (1, 'a')
'a'

We will add our newly crafted expression to the LearningDataAnalysis01 module. Now, open the file and add the new function towards the end of this file using the following code:

-- Finds the indices of every vowel in a word.
vowelIndices :: String -> [Integer]
vowelIndices word = 
  map fst $ filter ((_, letter) -> elem letter "aeiouAEIOU") $ zip [1..] word

Then, return to the Haskell command line and load the module using :l:

> :l LearningDataAnalysis01
[1 of 1] Compiling LearningDataAnalysis01 ( LearningDataAnalysis01.hs, interpreted )
Ok, modules loaded: LearningDataAnalysis01.

In the next few chapters, we will clip the output of the load command. Your functions are now loaded and ready for use on the command line:

> vowelIndices "apple"
[1,5]
> vowelIndices "orange"
[1,3,6]
> vowelIndices "grapes"
[3,5]
> vowelIndices "supercalifragilisticexpialidocious"
[2,4,7,9,12,14,16,19,21,24,25,27,29,31,32,33]
> vowelIndices "why"
[]

You can also use the median function that we used earlier. In the following code, we will pass every integer returned by vowelIndices through fromIntegral to convert it to a Double type:

> median . map fromIntegral $ vowelIndices "supercalifragilisticexpialidocious"
20.0

If you make changes to your module, you can quickly reload the module in the interactive command line by using :r. This advice comes with a warning—every time you load or reload a library in Haskell, the entire environment (and all your delicately typed expressions) will be reset. You will lose everything on doing this. This is typically countered by having a separate text editor open where you can type out all your Haskell commands and paste them in the GHCi interpreter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset