Online Book Reader

Home Category

Learn You a Haskell for Great Good! - Miran Lipovaca [46]

By Root 420 0

,("bonnie", "452-2928")

,("patsy", "493-2928")

,("patsy", "943-2929")

,("patsy", "827-9162")

,("lucille", "205-2928")

,("wendy", "939-8282")

,("penny", "853-2492")

,("penny", "555-2111")

]

If we just use fromList to put that into a map, we’ll lose a few numbers! Instead, we’ll use another function found in Data.Map: fromListWith. This function acts like fromList, but instead of discarding duplicate keys, it uses a function supplied to it to decide what to do with them.

phoneBookToMap :: (Ord k) => [(k, String)] -> Map.Map k String

phoneBookToMap xs = Map.fromListWith add xs

where add number1 number2 = number1 ++ ", " ++ number2

If fromListWith finds that the key is already there, it uses the function supplied to it to join those two values into one and replaces the old value with the one it got by passing the conflicting values to the function:

ghci> Map.lookup "patsy" $ phoneBookToMap phoneBook

"827-9162, 943-2929, 493-2928"

ghci> Map.lookup "wendy" $ phoneBookToMap phoneBook

"939-8282"

ghci> Map.lookup "betty" $ phoneBookToMap phoneBook

"342-2492, 555-2938"

We could also first make all the values in the association list singleton lists and then use ++ to combine the numbers:

phoneBookToMap :: (Ord k) => [(k, a)] -> Map.Map k [a]

phoneBookToMap xs = Map.fromListWith (++) $ map (\(k, v) -> (k, [v])) xs

Let’s test this in GHCi:

ghci> Map.lookup "patsy" $ phoneBookToMap phoneBook

["827-9162","943-2929","493-2928"]

Pretty neat!

Now suppose we’re making a map from an association list of numbers, and when a duplicate key is found, we want the biggest value for the key to be kept. We can do that like so:

ghci> Map.fromListWith max [(2,3),(2,5),(2,100),(3,29),(3,22),(3,11),(4,22),(4,15)]

fromList [(2,100),(3,29),(4,22)]

Or we could choose to add together values that share keys:

ghci> Map.fromListWith (+) [(2,3),(2,5),(2,100),(3,29),(3,22),(3,11),(4,22),(4,15)]

fromList [(2,108),(3,62),(4,37)]

So, you’ve seen that Data.Map and the other modules provided by Haskell are pretty cool. Next, we’ll look at how to make your own module.

Making Our Own Modules

As I said at the beginning of this chapter, when you’re writing programs, it’s good practice to take functions and types that work toward a similar purpose and put them in a separate module. That way, you can easily reuse those functions in other programs by just importing your module.

We say that a module exports functions. When you import a module, you can use the functions that it exports. A module can also define functions that it uses internally, but we can see and use only the ones that it exports.

A Geometry Module


To demonstrate, we’ll create a little module that provides some functions for calculating the volume and area of a few geometrical objects. We’ll start by creating a file called Geometry.hs.

At the beginning of a module, we specify the module name. If we have a file called Geometry.hs, then we should name our module Geometry. We specify the functions that it exports, and then we can add the functions. So we’ll start with this:

module Geometry

( sphereVolume

, sphereArea

, cubeVolume

, cubeArea

, cuboidArea

, cuboidVolume

) where

As you can see, we’ll be doing areas and volumes for spheres, cubes, and cuboids. A sphere is a round thing like a grapefruit, a cube is like a game die, and a (rectangular) cuboid is like a box of cigarettes. (Kids, don’t smoke!)

Now let’s define our functions:

module Geometry

( sphereVolume

, sphereArea

, cubeVolume

, cubeArea

, cuboidArea

, cuboidVolume

) where

sphereVolume :: Float -> Float

sphereVolume radius = (4.0 / 3.0) * pi * (radius ^ 3)

sphereArea :: Float -> Float

sphereArea radius = 4 * pi * (radius ^ 2)

cubeVolume :: Float -> Float

cubeVolume side = cuboidVolume side side side

cubeArea :: Float -> Float

cubeArea side = cuboidArea side side side

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

cuboidVolume a b c = rectArea a b * c

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

cuboidArea a b c = rectArea a b * 2 + rectArea a c * 2 +

rectArea

Return Main Page Previous Page Next Page

®Online Book Reader