在monadic上下文中使用Data.Map

atl*_*tis 3 monads haskell map

我正在操作的地图具有monadic键(类型IO Double).我需要findMax在这张地图上使用.我可以用liftM它吗?

Map.findMax $ Map.fromList [(f x, "X"), (f y, "Y"), (f z, "Z")]
Run Code Online (Sandbox Code Playgroud)

这里f x有类型IO Double.

Ste*_*ans 8

IO-typed值作为映射中的键是没有意义的.IO t某种类型的类型值t可以被认为是一个"程序",t每次运行时都会生成一个类型的值:您可以多次运行它,每次它可以生成不同的值.

所以,想要你可能想要的是先运行"程序"来获得一些结果; 这些结果可以成为地图的关键.

例如,如果你有一个"程序"

f :: Int -> IO Int
Run Code Online (Sandbox Code Playgroud)

这需要整数和计算,可能有效,整数,你需要运行输入[1 .. 10]来获取地图的键,你可以按如下方式进行:

createMap :: IO (Map Int Int)
createMap = do
  keys <- mapM f [1 .. 10]
  return $ foldr (\k -> Map.insert k (g k)) Map.empty keys
Run Code Online (Sandbox Code Playgroud)

这假定值是通过函数从键计算的

g :: Int -> Int
Run Code Online (Sandbox Code Playgroud)

createMap生成从整数到整数的映射; 它在IO-monad中返回它,因为用于填充映射的键可能受f运行"程序"的环境的影响.

你的问题

在您的情况下,这意味着您要计算的最大值也必须在IO-monad中生成:

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

逐步构建地图

当然,地图不需要一次创建,但也可以逐步构建:

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
Run Code Online (Sandbox Code Playgroud)


ehi*_*ird 5

您应该在插入地图之前执行monadic操作,如下所示:

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

哪里

calculateKey :: Value -> IO Key
Run Code Online (Sandbox Code Playgroud)