我正在操作的地图具有monadic键(类型为IO Double
)。我需要在此地图上使用findMax
。我可以使用liftM
吗?
Map.findMax $ Map.fromList [(f x, "X"), (f y, "Y"), (f z, "Z")]
此处f x
的类型为IO Double
。
答案 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