在单子上下文中使用Data.Map [英] Using Data.Map in monadic context
问题描述
我正在操作的地图具有单键(类型为IO Double
).我需要在这张地图上使用findMax
.我可以为此使用liftM
吗?
A map that I am operating on has monadic keys (of type IO Double
). I need to use findMax
on this map. Can I use liftM
for this?
Map.findMax $ Map.fromList [(f x, "X"), (f y, "Y"), (f z, "Z")]
此处f x
的类型为IO Double
.
推荐答案
在地图中使用IO
类型的值作为键实际上没有任何意义.某些类型t
的类型IO t
的值可以被认为是一个程序",它每次运行时都会产生类型t
的值:您可以多次运行它,并且每次可能会产生一个t
类型值.不同的值.
It doesn't really make sense to have IO
-typed values as keys in a map. A value of type IO t
for some type t
can be thought of as a "program" that produces a value of type t
each time it is run: you can run it multiple times and every time it may produce a different value.
因此,您可能想要首先运行程序"以获得一些结果;这些结果便可以成为地图的关键.
So, want you probably want is to first run the "program" to obtain some results; these results then can be the keys of your map.
例如,如果您有一个程序"
For example, if you have a "program"
f :: Int -> IO Int
需要整数并计算(可能有效地是整数),并且您需要在[1 .. 10]
的输入上运行才能获取地图的键,您可以按以下步骤进行操作:
that takes integers and computes, potentially effectfully, integers, and you need to run in on inputs from [1 .. 10]
to obtain the keys of your map, you could proceed as follows:
createMap :: IO (Map Int Int)
createMap = do
keys <- mapM f [1 .. 10]
return $ foldr (\k -> Map.insert k (g k)) Map.empty keys
这假定值是通过函数从键计算的
This assumes that the values are computed from the keys by a function
g :: Int -> Int
createMap
产生从整数到整数的映射;它会在IO
-monad中返回它,因为使用哪个键填充地图可能受运行程序" f
的环境的影响.
createMap
produces a map from integers to integers; it returns it in the IO
-monad, because which keys are used to populate the map is possibly subject to the environment in which the "program" f
was run.
在您的情况下,这意味着要计算的最大值也必须在IO
-monad中产生:
In your situation, this means that the maximal value you want to compute, has to be produced in the IO
-monad as well:
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))
逐步构建地图
当然不必一次性创建地图,但也可以增量构建:
Constructing the map incrementally
The map of course does not need to be created in one go, but can also be constructed incrementally:
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
这篇关于在单子上下文中使用Data.Map的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!