微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

具有组合查找和更新的地图记录?

如何解决具有组合查找和更新的地图记录?

一些伪代码

data A = A
data B = B
data C = C
data D = D
data E = E
data F = F
data G = G

data A1 = A1 A B C
data A2 = A2 A
data A3 = A3 B C D
data A4 = A4 D E F
data A5 = A5 A1 A4 G

data Foo k = Foo
    {
        a1s :: Map.Map k A1,a2s :: Map.Map k A2,a3s :: Map.Map k A3,a4s :: Map.Map k A4,a5s :: Map.Map k A5,--and my attempted solution would use
        -- e.g. [(A1,[(A,Unit),(B,(C,Unit)]),(A5,[(A1,Composite),(A4,(G,Unit) ]) ]
        componentMap :: Map.Map Type (Set Type),-- e.g. [(A,[A1,A2]),(A1,[A5,A1]) ]
        compositeMap :: Map.Map Type (Set Type)
    }

我想构建某种看起来像这样的数据结构。从这里,我想:

  • lookup :: Foo k -> k -> Either FailureReason v 单个值;如果我们假设我们已经填充了地图,我想要 lookup foo a1 :: A1,但也需要传递实例,例如 lookup foo a1 :: Blookup foo a5 :: A1(因为这是 getA1fromA5 $ lookup foo a5 的简写)和 { {1}}。我正在考虑 lookup foo a5 :: B 但这可能有点过分了。
  • 遍历类型,例如对 FailureReason = WrongType | NotPresent 的(索引)遍历,它应该命中 (k,D) 中的所有内容

这可以实现为对 A3,A4,A5componentMap 的递归搜索......只要它们是手动填充的。

由于上面看起来非常递归,我觉得这有一个 compositeMap 解决方案。可能是 GHC.Generics 吗?

或者我的解决方案是不需要 lens/optics + generic-lens/generic-optics 之类的,而只是编写一些遍历和镜头来索引我的结构?

问题变成了:这个功能是否已经存在于某个库中?如果不是,generics 是我正在寻找的工具吗?

解决方法

我假设您实际上并不需要多个映射——也就是说,给定的键应该只对应一个值,而不是 A1 映射中的 a1s 值和另一个 {来自 A2 地图等的 {1}} 值

此外,如果单个值中有多个特定类型的匹配项,您还没有说明要做什么,例如,如果您有类型的值:

a2s

并尝试检索或遍历 data A6 = A6 A3 A4 类型的术语。下面,我假设您只想检索和/或遍历遇到的“第一个”(例如,仅 D 中的 D,忽略 A3 中的那个)。

无论如何,您可以使用 A4 泛型和来自 Datalens 的一些助手来完成此操作。

不需要特殊的数据类型。一个普通的 Data.Data.Lens 就足够了,用 sum 类型来表示要存储的值的集合:

Map

要通过键查找(可能是深度嵌套的)值,我们可以使用 data Dat = D_A1 A1 | D_A2 A2 | D_A3 A3 | D_A4 A4 | D_A5 A5 deriving (Data) type Foo k dat = Map k dat 中的 biplate 遍历:

lens

这里,lookupFoo :: (Ord k,Typeable v,Data dat) => k -> Foo k dat -> Maybe v lookupFoo k foo = do dat <- Map.lookup k foo firstOf biplate dat 递归遍历词项 biplate 中所有类型为 v 的子词项。 dat 查询返回第一个匹配的术语,如果未找到术语,则返回 firstOf。 (Nothing 块在 do monad 中运行。)

要执行索引遍历,我们还可以使用 Maybe,修改后使用 biplate 仅遍历第一个匹配项:

taking 1

完整代码:

itraverseFoo :: (Applicative f,Data dat) => (k -> v -> f v) -> Foo k dat -> f (Foo k dat)
itraverseFoo f foo = Map.traverseWithKey f' foo
  where f' k dat = taking 1 biplate (f k) dat

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。