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.