Using Data.Map in a monadic context

The card I'm working on has monadic keys (like IO Double ). I need to use findMax on this map. Can I use liftM for this?

 Map.findMax $ Map.fromList [(fx, "X"), (fy, "Y"), (fz, "Z")] 

Here fx is of type IO Double .

+3
source share
2 answers

Actually, it makes no sense to have IO -type values โ€‹โ€‹as keys on the map. A value of type IO t for a certain type of t can be considered as a โ€œprogramโ€ that produces a value of type t every time it starts: you can run it several times and every time it can create a different value.

So, you want you to probably want to run the โ€œprogramโ€ first to get some results; these results can then be the keys of your card.

For example, if you have a "program"

 f :: Int -> IO Int 

which takes integers and calculates potentially effectively integers, and you need to run on inputs from [1 .. 10] to get the keys of your card, you can proceed as follows:

 createMap :: IO (Map Int Int) createMap = do keys <- mapM f [1 .. 10] return $ foldr (\k -> Map.insert k (gk)) Map.empty keys 

This assumes that the values โ€‹โ€‹are calculated using the keys using the function

 g :: Int -> Int 

createMap creates a map from integers to integers; he returns it to IO -monad, because which keys are used to populate the card may depend on the environment in which the โ€œprogramโ€ was launched f .

Your problem

In your situation, this means that the maximum value you want to calculate must be created in IO -monad:

 getMax :: Int -> Int -> Int -> IO (Double, String) getMax xyz = do keys <- mapM f [x, y, z] let entries = zip keys ["X", "Y", "Z"] return (Map.findMax (Map.fromList entries)) 

Building a display step by step

A map, of course, should not be created at a time, but can also be built gradually:

 f :: Int -> IO Int f = ... g :: Int -> Int g = ... createMap :: IO (Map Int Int) createMap = do -- create the empty map let m0 = Map.empty -- insert an entry into the map k1 <- f 1 let m1 = Map.insert k1 (g k1) m0 -- extend the map with another entry k2 <- f 2 let m2 = Map.insert k2 (g k2) m1 -- return the map return m2 
+8
source

You must perform a monadic action before inserting into the card, for example:

 insertValue :: Value -> Map Key Value -> IO (Map Key Value) insertValue value m = do key <- calculateKey value return $ Map.insert key value m 

Where

 calculateKey :: Value -> IO Key 
+5
source

Source: https://habr.com/ru/post/1396119/


All Articles