Goal of Part Two

Process Hash (Key-Value Pair) Loop by Iterating on List

This is the topic after previous section about Array (list).


Example of Doing Loop in Haskell With Map

This tutorial/ guidance/ article is one of three parts. These three combined is going to be a long article. So I won’t speak too much. More on codes, than just words.

The first two parts discuss the most common loop, array in part one and hash in part two. Considering that combining map with function is tricky, This deserve this an article of its own in part three. Part three also contains comparation with other Languages, using Real World Function.


Using Tuplets as a Pair of Key and Value

Tuplets can contain many elements. Let’s consider tuples contain two element below. We are going to use it as a base for our hash later.

pair :: (String, String)
pair = ("key", "value")

We can use standar method fst to access first element. And snd to access second element.

main = do
    print $ fst pair
    print $ snd pair

The use $ infix operator is used to avoid parantheses (round bracket). It is actually just print(fst(pair)). I just feel that Haskell syntax is sophisticatedly clearer.

And the result is:

"key"
"value"

Alternative Data Structure

There are other tricks to build hash dictionary, rather than use standard tuples. I suggest you to take a look at the code below to examine the possibility.


Accessing Using Pattern Matching

We can recreate our very own special function that behave like those two standard method above. And also get rid of the double tick quotation mark in output by using putStrLn.

In pattern matching _, means any value. Or just don’t care about it.

key   :: (String, String) -> String
key   (k, _) = k

value :: (String, String) -> String
value (_, v) = v

main = do
    putStrLn $ key pair
    putStrLn $ value pair
    putStrLn ""

And the result is slightly different:

key
value

If you do not like the complexity, you can wrap these two function putStrLn $ key, and leave the argument outside.

pair :: (String, String)
pair = ("key", "value")

putKeyLn :: (String, String) -> IO ()
putKeyLn (k, _) = do
    putStrLn k
    
main = do
    putKeyLn pair

This will produce:

key

View Source File:


Defining Hash

Let us turn our pair of associative key-value, into a more useful row of pairs. There many terminology for this, you can call it associative array, or hash, or dictionary. Consider this color scheme, that I borrow from google material color.

colorSchemes :: [(String, String)]
colorSchemes =
    [("blue50",     "#e3f2fd")
    ,("blue100",    "#bbdefb")
    ,("blue200",    "#90caf9")
    ,("blue300",    "#64b5f6")
    ,("blue400",    "#42a5f5")
    ,("blue500",    "#2196f3")
    ,("blue600",    "#1e88e5")
    ,("blue700",    "#1976d2")
    ,("blue800",    "#1565c0")
    ,("blue900",    "#0d47a1")
    ]
I do not put all the google material colors.
That is just a too long list to be included here.

Accessing Element

Accessing element of hash using index, has the same syntax with previous lesson. After all it is just list of pairs.

main = do
    print (colorSchemes !! 2)

This will produce:

("blue200","#90caf9")

Iterate with mapM_

So is using side effect with mapM_. It is as simple as the previous example.

main = mapM_ print colorSchemes

This will produce:

("blue50","#e3f2fd")
("blue100","#bbdefb")
("blue200","#90caf9")
("blue300","#64b5f6")
("blue400","#42a5f5")
("blue500","#2196f3")
("blue600","#1e88e5")
("blue700","#1976d2")
("blue800","#1565c0")
("blue900","#0d47a1")

Iterate with map

How about producing new list with map?

main = do
    print $ map fst colorSchemes
    putStrLn ""

Thsi will print raw list value. Each newly produced element is first tuples element. The key of pair.

["blue50","blue100","blue200","blue300","blue400","blue500","blue600","blue700","blue800","blue900"]

Chaining Function

As our need grow, we might desire to use chain functions This will accept the sequence of function as a whole compound operation.

main = do
    mapM_ (print . fst) colorSchemes
    putStrLn ""

    mapM_ (putStrLn . snd) colorSchemes
    putStrLn ""

These both map will show, raw of keys (first element), and later unquoted values (second element):

"blue50"
"blue100"
"blue200"
"blue300"
"blue400"
"blue500"
"blue600"
"blue700"
"blue800"
"blue900"

#e3f2fd
#bbdefb
#90caf9
#64b5f6
#42a5f5
#2196f3
#1e88e5
#1976d2
#1565c0
#0d47a1

Iterate Custom Function with mapM_

Furthermore as the code growing in need of more action, it is more clear to create new function. Here we have an example of an IO action procedure.

putPairLn :: (String, String) -> IO ()
putPairLn (key, value) = do
    putStrLn(key ++ " | " ++ value)

main = do    
    mapM_ putPairLn colorSchemes

This will display:

blue50 | #e3f2fd
blue100 | #bbdefb
blue200 | #90caf9
blue300 | #64b5f6
blue400 | #42a5f5
blue500 | #2196f3
blue600 | #1e88e5
blue700 | #1976d2
blue800 | #1565c0
blue900 | #0d47a1

Iterate Custom Function with map

And here it is, mapping function counterpart. Producing new list first as a feed to output.

pairStr :: (String, String) -> String
pairStr (key, value) = key ++ " | " ++ value

main = do
    mapM_ putStrLn (map pairStr colorSchemes)
    putStrLn ""   

This will show the same result as above.

While doing mapM_ after map seems redundant. It is just an example required in this tutorial, not everything have to be printed out.


Returning as IO

Many times we need to return value to IO, we just need to return in action and <- operator to call that action.

pairStrIO :: (String, String) -> IO String
pairStrIO (key, value) = do return (key ++ " | " ++ value)

main = do
    myPair <- pairStrIO ("myKey", "myValue")
    putStrLn myPair

Note that you can omit do notation for one liner in action.

This will show:

myKey | myValue

You can use Monad directly. If you are curious about bind >>=.

main = pairStrIO ("myKey", "myValue") >>= putStrLn

Or the flipped version =<<.

main = putStrLn =<< pairStrIO ("myKey", "myValue")  

Iterate Custom Function with mapM

In case we need both IO side effect and list result, we can use mapM

main = do
    myMapResult <- mapM pairStrIO colorSchemes
    putStrLn $ show myMapResult
    putStrLn "" 

This will produce text as below:

["blue50 | #e3f2fd","blue100 | #bbdefb","blue200 | #90caf9","blue300 | #64b5f6","blue400 | #42a5f5","blue500 | #2196f3","blue600 | #1e88e5","blue700 | #1976d2","blue800 | #1565c0","blue900 | #0d47a1"]

You might also consider using bind operator directly, as a oneliner vanilla monadic code..

main = (mapM pairStrIO colorSchemes) >>= (putStrLn . show)

Or the flipped version.

main = (putStrLn . show) =<< (mapM pairStrIO colorSchemes)

Of course, this is just a simple example on how to use mapM.


View Source File:


I hope it is clear, on how simple map is, compare to for loop counterpart.

However, combining map with function is tricky. This topic deserve an article of its own.

In “Part Three” we will discuss on writing function beyond loop.

Happy Coding.