使Data.Map成为逆变仿函数

时间:2016-11-19 23:54:14

标签: haskell functor category-theory

由于Data.Map.Map约束,

Ord key =>不是逆变函子。但我们可以将它与辅助函数打包成一个存在主义:

{-# LANGUAGE GADTs #-}
import qualified Data.Map as M
import Data.Profunctor

data MapPK k v where
    MapPK :: Ord i => (k -> i) -> M.Map i v -> MapPK k v

instance Profunctor MapPK where
    dimap f g (MapPK ff mm) = MapPK (f `lmap` ff) (g `fmap` mm)

我使用了Profunctor,但这是技术细节:lmap f = dimap f idcontramap。我还使用lmap (->) a b的{​​{1}}实例,如果它令人困惑,请抱歉。

MapPK在实践中非常有用 - 它本质上是一个带有计算键的映射,因此它浪费了CPU周期但可以节省空间。我们可以为它实现Data.Map.lookup

lookupPK k (MapPK f m) = M.lookup (f k) m

我想把这个想法变成一个库。关于现代键值容器界面的任何提示?对于MapPK通常有用,应该实现更多功能(例如插入 - 删除)。

然而,重用Data.Map中的函数名称对我来说似乎很古怪。我应该考虑提供Data.Lens.At个实例吗?

来自Data.Containers.IsMap

更新:mono-traversable无法实现,因为无法获取密钥列表。折叠/遍历也不能。我们甚至无法show我们的“地图”。

从某种意义上说,MapPK不再是普通地图,而是与type FunctionalMap k v = k -> Maybe v一起属于类似奇怪地图的类别。

尽可能枚举值并不是很有用。如果f = const 5,地图最多只包含一个值,那么内部Data.Map中的大多数值都是垃圾,但我们无法知道。

即使我们能够神奇地反转f这对我们没有多大帮助,因为逆并不总是存在,即使它存在非单调f碰巧有问题反过来。

请注意,我们也获得了一些功能。与FunctionalMap不同,我们的insert可以像Data.Map一样有效地实施。与Data.Map不同,一些奇特的键是可能的 - 现在我们可以将函数作为键。但并非所有 - IO Int都可以用作FunctionalMap中的“关键字”,但不能用于MapPK

0 个答案:

没有答案