在monadic上下文中使用Data.Map

时间:2011-12-20 12:16:22

标签: haskell map monads

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

Map.findMax $ Map.fromList [(f x, "X"), (f y, "Y"), (f z, "Z")]

此处f x的类型为IO Double

2 个答案:

答案 0 :(得分:8)

IO - 类型的值作为地图中的键是没有意义的。对于某些类型IO t,类型t的值可以被视为“程序”,每次运行时都会生成类型t的值:您可以多次运行它每次它可能产生不同的价值。

所以,希望你可能想要先运行“程序”来获得一些结果;这些结果可以成为地图的关键。

例如,如果您有“程序”

f :: Int -> IO Int

采用整数和计算,可能有效地整数,并且您需要在[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

这假设值是通过函数

从键计算的
g :: Int -> Int

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))

以递增方式构建地图

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

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

答案 1 :(得分:5)

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

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

,其中

calculateKey :: Value -> IO Key