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:
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:
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:
View Source File:
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 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:
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.
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.