# Loop in Haskell With Map, Part Three

Article Series
Where to Discuss?

Local Group

Table of Content

### Goal of Part Three

Process Hash (Key-Value Pair) with Haskell Function

We have seen an introduction of handling map with function in the previous lesson. Since combining map with function is tricky, and also contain many forms of syntatic sugar. This deserve this long explanation article.

### 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.

### Data Type Naming

Considering we might use a lot of (String, String) in our code. It is a good idea to use synonim, to avoid repetitive typing. This Pair type define tuples with two elements.

``````type Pair = (String, String)

pair :: Pair
pair = ("key", "value")``````

### Passing Arguments to Action

``````Think Action in Haskell as Procedure, Sequence of Command
``````

Now we can apply our Pair to new function. This function has two arguments.

• First, a text argument, with String type.

• Second, a tuples, with Pair type.

Since it is an IO action procedure, it must return IO (). This action looks like a void function, but it is actually not.

``````dumpPair :: String -> Pair -> IO ()
dumpPair text (key, value) = do
putStrLn(text ++ ": " ++ key ++ " | " ++ value)

main = do
dumpPair "Test" ("Key", "Value")``````

This will do display:

``Test: Key | Value``

### Reintroduce Data Structure

Considering our material color again, just in case we forget, or too lazy to scroll to previous part.

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

### Iterate with mapM_ using Curry Function

Now we can do iterate our latest function. Doing mapM_ inside a function.

This function has two arguments.

• First, a text argument, with String type.

• Second, a dictionary, with Pair type.

``````dumpHash1 :: String -> [Pair] -> IO ()
dumpHash1 text dictionary = do
mapM_ (dumpPair text) dictionary

main = do
dumpHash1 "Name" colorSchemes``````

Wait … !??*@…?? Doesn’t it defined earlier, that dumpPair has two arguments ?

The trick in passing argument rely in the closing bracket. (dumpPair text). It is called Curry Function. Based on mathematical Lambda Calculus. Since I’m a just another beginner, I suggest you to read about Haskell Curry Function somewhere else.

However, the result will echo as below:

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

It works. And plain simple.

### Using Lambda with mapM_

This is the trickiest part for beginner. But I must go on, because we will likely to see, a bunch of lambda everywhere, randomly marching, in any Haskell source code we meet. It is because lambda oftenly used as a wrapper of building block.

We can move above function dumpPair inside dumpHash2 function, using where clause. This way dumpPair won’t pollute global namespace.

``````dumpHash2 :: String -> [Pair] -> IO ()
dumpHash2 text dictionary = do
mapM_ (dumpPair' text) dictionary
where
dumpPair' text (key, value) = do
putStrLn(text ++ ": " ++ key ++ " | " ++ value)``````

And convert it to lambda later on. Merge both above function dumpPair and dumpHash1 into one dumpHash3.

``````dumpHash3 :: String -> [Pair] -> IO ()
dumpHash3 text dictionary = do
mapM_ (\(key, value) -> do
putStrLn(text ++ ": " ++ key ++ " | " ++ value)
) dictionary   ``````

It looks exactly like foreach loop, with different syntax. Once we get it, it is more flexible.

### Eta Reduction

And Hey, there is always a place for improvement. How about Eta Reduction. Ough.. Yeah…

``````dumpHash3 :: String -> [Pair] -> IO ()
dumpHash3 text = do
mapM_ (\(key, value) -> do
putStrLn(text ++ ": " ++ key ++ " | " ++ value)
)   ``````

Does it look literally cryptic, with operator marching, scattered all over the place ? Not really, the most cryptic part is the function declaration. This function declaration part is not mandatory. You can safely remove in this situation. Or just comment it out to disable.

### Side Effects: Debugging

I actually use this function as a based model, to read key-value pairs from config. Sometimes strange thing happen in my application, and I need too see what happened in the process of applying config.

So what if I want some kind IO operation inside, such debug debug for example. Well, here it is, how to do it. No need to worry about side efect, we are already in IO action mode.

``````dumpHash4 :: String -> [Pair] -> IO ()
dumpHash4 text dictionary = do
-- loop over a hash dictionary of tuples
mapM_ (\(key, value) -> do
let message = text ++ ": " ++ key ++ " | " ++ value

putStrLn message

-- uncomment to debug in terminal
-- putStrLn ("Debug [" ++ message ++ "]")
) dictionary  ``````

Note that in real application, I replace the line putStrLn message with my own IO action.

### Passing Arguments to Function

``````Think Function in Haskell as Math Equation
``````

Now we can apply our Pair to new function. This function has two arguments, and one returning value.

• First, a text argument, with String type.

• Second, a tuples, with Pair type.

• Return String Type.

``````pairMessage :: String -> Pair -> String
pairMessage text (key, value) =
text ++ ": " ++ key ++ " | " ++ value

main = do
putStrLn \$ pairMessage "Test" ("Key", "Value")
putStrLn ""``````

This will show display:

``Test: Key | Value``

The difference betwwen pairMessage with the function dumpPair is, we place IO operation such putStr outside the function.

### Iterate with map using Curry Function

Now we can do iterate our latest function. Doing map inside a function.

This function has two arguments, and one returning value.

• First, a text argument, with String type.

• Second, a dictionary, with List of Pair.

• Return List of String.

``````hashMessage1 :: String -> [Pair] -> [String]
hashMessage1 text dictionary =
map (pairMessage text) dictionary

main = do
mapM_ putStrLn (hashMessage3 "Name" colorSchemes)
putStrLn ""``````

You should not be surprised with the curry function pairMessage text. This wil produce as below:

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

It also works. And plain simple.

### Using Lambda with map

We can move above function pairMessage inside hashMessage2 function, using where clause.

``````hashMessage2 :: String -> [Pair] -> [String]
hashMessage2 text dictionary =
map (pairMessage' text) dictionary
where
pairMessage' text (key, value) =
text ++ ": " ++ key ++ " | " ++ value``````

And convert it to lambda later on. Merge both above function pairMessage and hashMessage1 into one hashMessage3.

``````hashMessage3 :: String -> [Pair] -> [String]
hashMessage3 text dictionary =
map ( \(key, value) ->
text ++ ": " ++ key ++ " | " ++ value
) dictionary

main = do
mapM_ putStrLn (hashMessage3 "Name" colorSchemes)
putStrLn ""``````

It looks exactly like foreach loop, with different syntax. Once we get it, it is more flexible.

### Go Further with Action

Considering of simpliying the main clause. How about moving mapM_ putStrLn inside an action? We should go back using IO action procedure, because main clause only accept IO sequence.

First we need to capture the value of newly produced list. Do block, contain only sequence of IO. We assign a variable in do block by using let clause.

``````-- function
dumpHash5 :: String -> [Pair] -> IO ()
dumpHash5 text dictionary = do
-- loop over a hash dictionary of tuples
let messages = map ( \(key, value) ->
text ++ ": " ++ key ++ " | " ++ value
) dictionary
mapM_ putStrLn messages

main = do
dumpHash5 "Name" colorSchemes
putStrLn ""``````

How about the output ? The same as previous sir.

We can go further using where as usual. No need to covert into lambda. We can have another form of this function.

``````dumpHash6 :: String -> [Pair] -> IO ()
dumpHash6 text dictionary = do
-- loop over a hash dictionary of tuples
forM_ messages putStrLn
where messages = map ( \(key, value) ->
text ++ ": " ++ key ++ " | " ++ value
) dictionary ``````

### Side Effects: Debugging

Again, how if I want multiple IO operation inside ? Such as debugging capability, after applying config. We can do it by changing from standard IO putStrLn to custom IO action debugStrLn inside where clause.

``````dumpHash7 :: String -> [Pair] -> IO ()
dumpHash7 text = do
-- loop over a hash dictionary of tuples
forM_ messages debugStrLn
where
debugStrLn message = do
putStrLn message

-- uncomment to debug in terminal
-- putStrLn ("Debug [" ++ message ++ "]")

messages = map ( \(key, value) ->
text ++ ": " ++ key ++ " | " ++ value
) dictionary ``````

You can try it yourself in your terminal.

### Conclusion

Coding in Haskell is fun. I love it.

Happy Coding.