I have a function whose signature is String -> String -> IO (Maybe String) Now I use this function to create values ββfor the dictionary, and as a result I get: [(String,IO (Maybe String))]
This part does not add up for me. How do you enter only 2 lines and end with a significant result like [(String, IO (Maybe String))] ?
With no data, let's assume your situation is something like this:
f :: String -> String -> IO (Maybe String) magic :: String -> (String, String)
magic takes some key and somehow breaks the key into two input lines needed for f . So, suppose you have a list of keys, you can use [(String, IO (Maybe String))] as follows:
-- ks :: [String] myMap = map (\k -> let (a,b) = magic k in (k, fab)) ks
But ... wouldn't it be better if there were [(String, Maybe String)] instead? Assuming we are inside the action of IO ...
someIOAction = do ... myMap <- monadicMagicks (\k -> let (a,b) = magic k in (k, fab)) ks
But what monadicMagicks could we use to do it right? Let's look at the types that we expect from these expressions.
monadicMagicks (\k -> ...) ks :: IO [(String, Maybe String)] (\k -> let (a,b) = magic k in (k, fab)) :: String -> (String, IO (Maybe String)) ks :: [String] -- therefore monadicMagicks :: (String -> (String, IO (Maybe String))) -> [String] -> IO [(String, Maybe String)]
Stop ... Google time. Let's first summarize what we are looking for. Here we have two main data types: String , which is represented as "input", and Maybe String , which is represented as "output". Therefore, replace String with a and Maybe String with b . So, we are looking for (a -> (a, IO b)) -> [a] -> IO [(a, b)] . Hmm No results found. Well, if we could only get the result type IO [b] , then in the do block we could get it from IO, and then zip with the original list of keys. It also means that the function we are inserting would not have to pair the key with the result. Therefore, let's simplify what we are looking for and try again: (a -> IO b) -> [a] -> IO [b] . Hey check it out! mapM matches this type signature fine.
monadicMagicks :: (a -> IO b) -> [a] -> IO [(a, b)] monadicMagicks f xs = do ys <- mapM f xs return $ zip xs ys
This can be written more concisely and with a more general signature like:
monadicMagicks :: Monad m => (a -> mb) -> [a] -> m [(a, b)] monadicMagicks f xs = zip xs `liftM` mapM f xs someIOAction = do ... -- Like we said, the lambda no longer has to pair up the key with the result myMap <- monadicMagicks (\k -> let (a,b) = magic k in fab) ks
This last line can also be rewritten a little shorter if you are comfortable with the composition of functions:
myMap <- monadicMagicks (uncurry f . magic) ks
Please note that monadicMagicks may not make much sense for some monads, so this is probably not in standard libraries. (For example, using mapM in a monad list usually means that the result will have a different length than the input):
ghci> mapM (\x -> [x, -x]) [1,2] [[1,2],[1,-2],[-1,2],[-1,-2]]