Chapter 7

Modules

Loading Modules

The Prelude module is imported by default and includes basic functions like the ones we have used so far.

The syntax for importing a module into a script is “Import <module name>"

You are also able to load specific functions from a module without loading the whole thing.

>Import Data.List (nub, sort)

If a function of a module is giving you problems or for some other reason you don’t want to load it you can do so by hiding it.

>importData.Listhiding(nub)

If you’re having namespace issues you’re able to use a qualified import to solve it.

importqualifiedData.Map

For the conflicted functions in Data.Map you must reference them by Data.Map.function. For instance if we want to use the filter function of Data.Map we would need to use Data.Map.filter

If we didn’t want to type Data.Map before every function we are able to use the keyword “as”.

importqualifiedData.MapasM

This allows you to use M.function instead of Data.Map.function

Let us try doing a function that is not imported yet.

>nub [1 ,3, 3, 3, 4, 4]

We get an error since the nub function is not loaded yet. We need to import the Data.List module

In order to import modules in the interactive mode you use :m + module1 module2

>:m + Data.List

>nub [1 ,3, 3, 3, 4, 4]

Notice that your imported modules are added to the prompt

The Haskell standard library can be found at http://www.haskell.org/ghc/docs/latest/html/libraries/

You can also use Hoogle (http://www.haskell.org/hoogle/ ) to search the library.

Data.List

This module defines list functions

>:m + Data.List

Intersperse takes an element and a list. It returns a list with the first element in between every element in the list

>intersperse ‘.’ “YMCA”

“Y.M.C.A”

Intercalate acts like Intersperse but takes a list and a list of a lists

>intercalate “ um “ [“hey”,”there”,”guys”]

“hey um there um guys”

Transpose transposes a matrix

>transpose [[1,2,3],[4,5,6],[7,8,9]]

[[1,4,7],[2,5,8],[3,6,9]]

Concatenates a list

>concat ["foo","bar","car"]

“foobarcar”

>concatMap(replicate4)[1..3]

[1,1,1,1,2,2,2,2,3,3,3,3]

‘And’ takes a list of boolean values and returns True only if all the values in the list are True.

>and$map(>4)[5,6,7,8]

True

>or$map(==4)[2,3,4,5,6,1]

True

A better way to do this would be using any or all. Any and all take a predicate and then check if any or all the elements in a list satisfy the predicate, respectively.

>any(==4)[2,3,5,6,1,4]

True

>all(>4)[6,9,10]

True

iterate takes a function and a starting value. It then applies the function to the initial value and continues on applying the function to the result returning an infinite list.

>take10$iterate(*2)1

[1,2,4,8,16,32,64,128,256,512]

splitAt splits at a given index

splitAt3"heyman"

("hey","man")

takeWhile takes elements from a list while the predicate holds and then when an element is encountered that doesn't satisfy the predicate, it's cut off.

>takeWhile(>3)[6,5,4,3,2,1,2,3,4,5,4,3,2,1]

[6,5,4]

Dropwhile is just like takewhile but drops elements until the predicate holds

>dropWhile(<3)[1,2,2,2,3,4,5,4,3,2,1]

[3,4,5,4,3,2,1]

Span loops through the list until the predicate doesn’t hold and then splits the list returns a pair of lists.

let(fw,rest)=span(/='')"Thisisasentence"in"Firstword:"++fw++",therest:"++rest

"Firstword:This,therest:isasentence"

Break is like span except it splits the list when the predicate first holds.

>break(==4)[1,2,3,4,5,6,7]

([1,2,3],[4,5,6,7])

You can guess what sort does

sort[8,5,3,2,1,6,4,2]

[1,2,2,3,4,5,6,8]

group takes a list and groups adjacent elements into sublists if they are equal.

group[1,1,1,1,2,2,2,2,3,3,2,2,2,5,6,7]

[[1,1,1,1],[2,2,2,2],[3,3],[2,2,2],[5],[6],[7]]

inits and tails are like init and tail, only they recursively apply that to a list until there's nothing left.

inits"w00t"

["","w","w0","w00","w00t"]

>tails"w00t"

["w00t","00t","0t","t",""]

isInfixOf, isPrefixOf, isSuffixOf takes a sublist and a lists and returns true if the sublist is in the list, at the beginning of the list, or end of the list respectively.

Partition takes a list and a predicate and returns a pair of lists. The first list in the result contains all the elements that satisfy the predicate, the second contains all the ones that don't.

>partition(`elem`['A'..'Z'])"BOBsidneyMORGANeddy"

("BOBMORGAN","sidneyeddy")

You may think this is identical to span but it’s not. Span stops as soon as the condition is false.

>span(`elem`['A'..'Z'])"BOBsidneyMORGANeddy"

("BOB","sidneyMORGANeddy")

find takes a list and a predicate and returns the first element that satisfies the predicate

>find(>4)[1,2,3,4,5,6]

Just5

Just 5? What does that mean?

>:t find

find::(a->Bool)->[a]->Maybea

Maybe? A maybe value can be ‘Just something’ or ‘Nothing’. It allows an expression to return nothing instead of an error.

ElemIndex It maybe returns the index of the element we're looking for.

>''` elemIndex `"Wherearethespaces?"

Just 5

But in order to get all of the Indices and not just the first we need to use elemIndices

>''`elemIndices`"Wherearethespaces?"

[5,9,13]

Zip3 and zip4 are just like zip but takes 3 lists and 4 lists instead of 2.

zip4[2,3,3][2,2,2][5,5,3][2,2,2]

[(2,2,5,2),(3,2,5,2),(3,2,3,2)]

lines separates a string by into a list of lines

lines"firstline\nsecondline\nthirdline"

["firstline","secondline","thirdline"]

The inverse of lines is unlines

Words separate words into a list

words"heythesearethewordsinthissentence"

["hey","these","are","the","words","in","this","sentence"]

The inverse of words is unwords

Delete, you guessed it deletes the first occurrence of an element in a list

>delete'h'"heythereghang!"

"eythereghang!"

\\ is the set diference

>[1..10]\\[2,5,9]

[1,3,4,6,7,8,10]

>[1..7]`union`[5..10]

[1,2,3,4,5,6,7,8,9,10]

[1..7]`intersect`[5..10]

[5,6,7]

insert inserts an element into a list. It attempts to put in in order by going through the list and inserting the element before an element that is equal or greater then it.

>insert4[3,5,1,2,8,2]

[3,4,5,1,2,8,2]

Note: length, take, drop, splitAt, !! and replicate use Int in their definition. So if you want to get the average of a list, a statement like “let xs = [1..6] in sum xs / length xs” will give a type error. In order to overcome obstacles like this, Data.List gives us genericLength, genericTake, genericDrop, genericSplitAt, genericIndex and genericReplicate

let xs = [1..6] in sum xs / length xs

Error

let xs = [1..6] in sum xs / genericLength xs

3.5

The nub, delete, union, intersect and group functions also have their more general counterparts called nubBy, deleteBy, unionBy, intersectBy and groupBy. The difference between them is that the first set of functions use == to test for equality, whereas the By ones also take an equality function and then compare them by using that equality function

Similarly, the sort, insert, maximum and minimum also have their more general equivalents. sortBy, insertBy, maximumBy and minimumBy take a function that determine if one element is greater, smaller or equal to the other.

Here we will sort a list of lists by their length

>letxs=[[5,4,5,4,4],[1,2,3],[3,5,4,3],[],[2],[2,2]]

sortBy(compare`on`length)xs

[[],[2],[2,2],[1,2,3],[3,5,4,3],[5,4,5,4,4]]

Data.Char

This module export functions that deal with characters

Below is a list of Data.Char functions that are Char -> Bool

isControl checks whether a character is a control character.

isSpace checks whether a character is a white-space characters. That includes spaces, tab characters, newlines, etc.

isLower checks whether a character is lower-cased.

isUpper checks whether a character is upper-cased.

isAlpha checks whether a character is a letter.

isAlphaNum checks whether a character is a letter or a number.

isPrint checks whether a character is printable. Control characters, for instance, are not printable.

isDigit checks whether a character is a digit.

isOctDigit checks whether a character is an octal digit.

isHexDigit checks whether a character is a hex digit.

isLetter checks whether a character is a letter.

isMark checks for Unicode mark characters. Those are characters that combine with preceding letters to form latters with accents. Use this if you are French.

isNumber checks whether a character is numeric.

isPunctuation checks whether a character is punctuation.

isSymbol checks whether a character is a fancy mathematical or currency symbol.

isSeparator checks for Unicode spaces and separators.

isAscii checks whether a character falls into the first 128 characters of the Unicode character set.

isLatin1 checks whether a character falls into the first 256 characters of Unicode.

isAsciiUpper checks whether a character is ASCII and upper-case.

isAsciiLower checks whether a character is ASCII and lower-case.

allisAlphaNum"bobby283"

True

allisAlphaNum"bobby 283"

False

Each Char falls into 1 of the 31 a general Categorys.

mapgeneralCategory"Ab\t\nA9?|"

toUpper converts a character to upper-case. Spaces, numbers, and the like remain unchanged.

toLower converts a character to lower-case.

toTitle converts a character to title-case. For most characters, title-case is the same as upper-case.

digitToInt converts a character to an Int. To succeed, the character must be in the ranges '0'..'9', 'a'..'f' or

intToDigit is the inverse function of digitToInt

The ord and chr functions convert characters to their corresponding numbers and vice versa:

>ord'a'

97

>chr 97

a

Data.Map

This module defines functions for association lists (AKA dictionary’s). It uses a tree structure under the hood so it’s more efficient then a list of tuples for looking up items.

>Let phoneBook=[("betty","555-2938"),("bonnie","452-2928"),("patsy","493-2928"),("lucille","205-2928"),("wendy","939-8282"),("penny","853-2492")]

LetphoneDict = Data.Map.fromList phonebook

Let phoneDict = Data.Map.insert “billy” “555-1234” phoneDict

>Map.member “billy” phoneDict

true

>Data.Map.lookup “billy” phoneDict

Just “555-1234”

null checks if a map is empty.

size reports the size of a map.

singleton takes a key and a value and creates a map that has exactly one mapping.

Data.Set

Remember in sets, all elements are unique. They are implemented as trees and are ordered.

Some common functions that Data.Set includes are:

Intersection ,difference, union, null, size, member, empty, singleton, insert, delete

Making our own Modules

When writing our own modules we must start off by saying what functions we are going to export. These are the functions that others can see when the module is imported.

moduleGeometry

> (sphereVolume

> ,sphereArea

> ,cubeVolume

> ,cubeArea

> ,cuboidArea

> ,cuboidVolume

> )where

After, the functions are declared.

> sphereVolume::Float->Float

> sphereVolumeradius=(4.0/3.0)*pi*(radius^3)

>

> sphereArea::Float->Float

> sphereArearadius=4*pi*(radius^2)

>

> cubeVolume::Float->Float

> cubeVolumeside=cuboidVolumesidesideside

>

> cubeArea::Float->Float

> cubeAreaside=cuboidAreasidesideside

>

> cuboidVolume::Float->Float->Float->Float

> cuboidVolumeabc=rectangleAreaab*c

>

> cuboidArea::Float->Float->Float->Float

> cuboidAreaabc=rectangleAreaab*2+rectangleAreaac*2+rectangleAreacb*2

>

> rectangleArea::Float->Float->Float

> rectangleAreaab=a*b

Remember to import a module you must be in the same directory as the module.