Dictionary Haskell映射:转换键和捕捉错误

Dictionary Haskell映射:转换键和捕捉错误,dictionary,haskell,error-handling,Dictionary,Haskell,Error Handling,我很难找到以下问题的解决方案(除了使用Data.Map.fromList和toList): 使用返回或字符串k的函数转换键,其中通常错误表示为Left,如果单个键转换失败,整个转换将失败 import Data.Map.Strict mapEitherKey :: (k -> Either String k') -> Map k a -> Either String (Map k' a) 对于Map k v的右侧v,使用mapM可以轻松完成,因为 mapk是Monad的一个

我很难找到以下问题的解决方案(除了使用
Data.Map.fromList
toList
):

使用返回
或字符串k
的函数转换键,其中通常错误表示为
Left
,如果单个键转换失败,整个转换将失败

import Data.Map.Strict

mapEitherKey :: (k -> Either String k') -> Map k a -> Either String (Map k' a)
对于
Map k v
的右侧
v
,使用
mapM
可以轻松完成,因为
mapk
Monad
的一个实例

但没有一个在键中提供任何函数。(例如,
Map
不是
Bifunctor
的一个实例,我想知道是否有更深层次的原因。我确实看到了这一点,因为需要考虑键冲突。)


任何见解都将不胜感激。

我想附和@chi所说的;除非您知道保留了顺序,否则每次都必须重新插入密钥。这意味着
toList
,然后使用
fromList
重新插入,应该是渐进获得的最佳结果

但是,由于您要求一种不使用这些函数的方法,我建议使用


由于键上的
Ord
约束,它不能是双Functor。此外,在键上应用任意函数可能会破坏树的不变性(函数可以是非单调的,也可以是非内射的),因此需要从头开始构造一棵新树,有效地使用类似
fromList/toList
。该库提供
mapKeys::Ord k2=>(k1->k2)->映射k1 a->映射k2 a
以了解键上的某些功能。它是O(n*logn)而不是O(n),因为需要重建树。如果你有一个单调函数,你可以使用
mapkeymonotonic::(k1->k2)->mapk1a->mapk2a
,它在O(n)中运行--小心不要破坏不变量。
import Data.Monoid (Ap(..))
import qualified Data.Map as M


mapEitherKey :: (Ord k, Ord k') => (k -> Either String k') -> Map k a -> Either String (Map k' a)
mapEitherKey f = getAp . M.foldMapWithKey (\k v -> Ap (flip M.singleton v <$> f k))
Prelude> f k = if k > 10 then Left "bad number" else Right $ show k
Prelude> mapEitherKey f (M.fromList [(0,0),(1,1),(2,2)])
Right (fromList [("0",0),("1",1),("2",2)])
Prelude> mapEitherKey f (M.fromList [(0,0),(1,1),(2,2),(11,11)])
Left "bad number"