Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looping through a map data structure in Haskell

I have a map data structure that has the following structure:- "What is the capital of UK"-> "London" "What is the capital of France"-> "Paris" I want to loop through this map displaying the question: "What is the capital of UK", asking for user input. If the user answers "London" I print correct, otherwise, I print the correct answer "London". This is easy in an imperative language like C# but I haven't figured how to do it in Haskell.

like image 732
user3480820 Avatar asked Jun 02 '26 22:06

user3480820


2 Answers

The issue with using Map in this manner is a lot of the traversals over Map values assume you don't care about the key and only care about the contained value. There are traversals inside Data.Map that suffice, and @danidiaz has pointed on out, but it's totally reasonable to call toList since that list will be generated lazily, not forced into memory all at once. Given a list of tuples (key, value) you can traverse that using for or mapM or fmap or .... basically any of the constructs you love so long as you can use an IO monad.

{-# LANGUAGE OverloadedLists #-}
import Data.Foldable (for_)
import Data.Map (Map,toList)

m :: Map String String
m = [("a","1"),("b","2")]

main =
  for_ (toList m) $ \(q,a) ->
    do putStrLn q
       x <- getLine
       putStrLn (if x == a
                    then "Yes"
                    else "No: " ++ a)

EDIT: I feel compelled to add what most people would call more idiomatic Haskell using mapM_:

main :: IO ()
main = mapM_ ask (toList m)

ask :: (String,String) -> IO ()
ask (q,a) = do putStrLn q
               x <- getLine
               putStrLn (if x == a then "Yes" else "No: " ++ a)
like image 93
Thomas M. DuBuisson Avatar answered Jun 04 '26 13:06

Thomas M. DuBuisson


lens's ifor_ combinator allows you to write @ThomasM.DuBuisson's code without going via toList. The traversal function gets access to the index at each iteration.

main = ifor_ m $ \(q, a) -> do
    putStrLn q
    x <- getLine
    putStrLn (if x == a then "Yes" else "No: " ++ a)
like image 24
Benjamin Hodgson Avatar answered Jun 04 '26 12:06

Benjamin Hodgson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!