Transcript Haskell 4
More Haskell Functions
Maybe, Either, List, Set, Map
26-Jul-16
Maybe
find (imported from Data.List) takes a predicate and a list, and returns
the first element that satisfies the predicate
But what if there is no such element?
Any Java method that supposed to return an object might instead return null
Thus, it is common to get NullPointerException
In Haskell, find returns a Maybe
find (> 40) [1..10]
In such a case, Java would return null
Example: find (> 4) [1..10]
find :: (a -> Bool) -> [a] -> Maybe a
A Maybe can have the value Nothing or Just something
find (>4) [1..10]
Just 5
find (> 40) [1..10]
Nothing
This works well when combined with pattern matching
Using Maybe
Maybe is a monad
For now, you can just think of it as a “wrapper”
The usual way to deal with monads like this is with a case expression
tell :: Maybe String -> String
tell arg = case arg of Just s -> "Yes, we have " ++ s
Nothing -> "No, sorry!"
GHCi> tell (Just "bananas")
"Yes, we have bananas"
GHCi> tell Nothing
"No, sorry!"
Either
Either takes two types: Either a b
buy :: String -> Int -> Either String Int
buy item cost =
if cost < 20 then Left ("Purchased " ++ item)
else Right cost
*Main> buy "lamp" 15
Left "Purchased lamp"
*Main> buy "sofa" 300
Right 300
Using Either
buy item cost =
if cost < 20 then Left("Purchased " ++ item)
else Right cost
tell_if_bought :: String -> Int -> String
tell_if_bought item price =
case buy item price of
Left s -> "Yes, " ++ s
Right i -> "$" ++ (show price) ++ " was too expensive."
GHCi> tell_if_bought "Sofa" 300
"$300 was too expensive."
GHCi> tell_if_bought "lamp" 16
"Yes, Purchased lamp"
Modules
A Haskell module is like a Java package
A module contains functions, types, and typeclasses
Unlike Java, there are a lot of name collisions, so modules often have to be
imported in a qualified way
To import into GHCi, use :m + module ... module
To import into a program, use import module
import module (f1,..., fn) will import only the named functions
import module hiding (f1,..., fn) will import all but the named
functions
import qualified module imports the module; we call an imported
function fn with module.fn
import qualified module as M imports the module; we call an
imported function fn with M.fn
Typeclasses
A Haskell typeclass is like a Java interface--it tells what
functions an object can support
Some typeclasses and what they support:
Eq -- == and /=
Ord -- < <= >= >
Num -- + - * / and others
Show -- show (enables printing as a string)
Read -- read (conversion from a string to something else)
Functor -- fmap (enables mapping over things)
Lists belong to the Functor typeclass
Monad -- >>=
>>
return
fail
Data.List I
The standard Prelude imports many Data.List functions for
us: map, filter, foldl, etc.
intersperse :: a -> [a] -> [a]
intercalate :: [a] -> [[a]] -> [a]
intercalate " and " ["one", "two", "three"]
"one and two and three"
transpose :: [[a]] -> [[a]]
intersperse ' ' "hello" "h e l l o”
transpose [[1,2,3],[4,5,6]] [[1,4],[2,5],[3,6]]
take 5 (iterate (* 2) 1) [1,2,4,8,16]
take 5 (drop 5 (iterate (* 2) 1)) [32,64,128,256,512]
take 5 $ drop 5 $ iterate (* 2) 1 [32,64,128,256,512]
takeWhile (/= ' ') "Hello there" "Hello"
dropWhile (/= ' ') "Hello there" " there"
Data.List II
The following are especially helpful when dealing with text:
span isLetter "one two three" ("one"," two three")
break isSpace "one two three" ("one"," two three")
words "Here are some words."
["Here","are","some","words."]
unwords $ words "Here are some words."
"Here are some words."
lines "Roses are red\nViolets are blue"
["Roses are red","Violets are blue"]
unlines $ lines "Roses are red\nViolets are blue"
"Roses are red\nViolets are blue\n"
Data.Char
Predicates:
isControl
isSpace (any whitespace)
isLower, isUpper
isAlpha, isAlphaNum, isDigit
isPunctuation
and others
Conversions:
toUpper, toLower, toTitle
digitToInt, intToDigit
ord, chr
Data.Map
Maps are constructed from lists of 2-tuples
Not using a Map:
*Main> let nums = [(1, "one"), (2, "two"), (3, "three"),
(4, "four"), (5, "five")]
*Main> lookup 3 nums
Just "three"
Using a Map:
*Main> let dict = Map.fromList nums
*Main> dict
fromList
[(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five")]
*Main> :t Map.fromList
Map.fromList :: (Ord k) => [(k, a)] -> Map.Map k a
*Main> Map.lookup 3 dict
Just "three"
*Main> Map.lookup 7 dict
Nothing
Map operations I
Maps in Haskell are implemented with binary trees, not with
hash tables
Map.empty -- returns an empty map
Map.null map -- tests if a map is empty
Map.singleton key value -- returns a map with one key/value
pair
Map.fromList list -- given a list of 2-tuples, returns a map
Hence, keys must belong to the Ord typeclass
Note: Only the last value is kept if a key is repeated
Map.insert key value map -- inserts a key/value pair
Map.size map -- returns the number of key/value pairs
Map.member key -- tests if the key is in the map
Map.lookup key -- returns Just value or Nothing
Map operations II
Map.map f map -- returns a map in which f has been applied to
each value
Map.filter f map -- returns a map containing only those
key/value pairs for which f value is True
Map.keys map -- returns a list of keys
Map.elems map -- returns a list of values
Map.toList map -- returns a list of (key, value) 2-tuples
Map.fromListWith f list -- given a list of 2-tuples, returns a
map; f is applied to combine duplicate values for the same key
Map.insertWith f key value -- inserts the key/value pair into
the map, using the function f to combine duplicate values for the
same key
Sets in Haskell
Sets, like Maps, are constructed from lists
The import should be qualified to avoid name collisions:
import qualified Data.Set as Set
This is also true for Maps:
import qualified Data.Map as Map
Set.fromList list -- returns a set created from a list
(duplicates are removed)
Set.toList set -- returns an ordered list from a set
Set operations
Set.empty
Set.null set
Set.member value set
Set.union set1 set2
Set.intersection set1 set2
Set.difference set1 set2
Set.size set
Set.singleton value
Set.insert value set
Set.delete value set
Set.map f set
Set.filter f set
Compiling a Haskell program
On UNIX (including Linux and Mac OS):
Compile with ghc --make filename (omit the .hs)
Run with ./filename
On Windows:
Set the PATH environment variable to something like C:\ghc\ghc6.6\bin
Compile with ghc inputfile -o outputfile
Also works on a Mac
compiling hello.hs results in hello.hi, hello.o, and main.exe
Run with outputfile.exe
Running as an interpreted program, without compiling:
runhaskell filename.hs
The End