关联列表的镜头

问题描述 投票:4回答:1

atMap / HashMap /等的Control.Lens.At镜头。但是任何镜头类似于at关联列表类型[(k, v)](可转换为地图)?

haskell lens
1个回答
7
投票

我不知道为你提供的那个,但at属于类型类At,所以我们当然可以自己写。为了避免使用灵活(可能重叠)的实例扩展来弄脏我们,我们将在newtype中执行此操作。

newtype AList k v = AList [(k, v)]

首先,我们需要一些家庭实例。

{-# LANGUAGE TypeFamilies #-}

type instance IxValue (AList k v) = v
type instance Index (AList k v) = k

这只是定义了我们新类型中“键”和“值”的含义,这很简单。现在,我们需要能够在特定键上读取和写入值。 Haskell已经为我们提供了一种读取值的方法(Data.List.lookup),但我们必须自己编写函数。没有什么花哨的或镜头在这里:只是普通的旧Haskell过滤器和地图。

replaceAt :: Eq k => k -> Maybe v -> AList k v -> AList k v
replaceAt k Nothing (AList m) = AList $ filter (\(k', _) -> k /= k') m
replaceAt k (Just v) (AList m) =
    case lookup k m of
      Nothing ->
          -- Not present in the list; add it
          AList ((k, v) : m)
      Just _ ->
          -- Present; replace it
          AList $ map (\(k', v') -> if k == k' then (k', v) else (k', v')) m

现在我们需要编写At实例,它依赖于Ixed实例。幸运的是,只要我们实现Ixed,镜头库就为At提供了默认实现,因此第一个实例声明很简单。

instance Eq k => Ixed (AList k v)

at也相当简单。只需看看类型并跟随你的鼻子,你得到的实现是我们想要的。

instance Eq k => At (AList k v) where
    at k f (AList m) = fmap (\v' -> replaceAt k v' (AList m)) $ f (lookup k m)

我们已经完成了。现在at将为AList工作。如果newtype包装器困扰你,你可以很容易地创建一个新函数(at',如果你愿意的话)为你做新类型包装/解包。

证明这个实例满足镜片定律是留给读者的练习。

完整的代码

{-# LANGUAGE TypeFamilies #-}

import Control.Lens.At
import Data.List(lookup)

newtype AList k v = AList [(k, v)]

type instance IxValue (AList k v) = v
type instance Index (AList k v) = k

replaceAt :: Eq k => k -> Maybe v -> AList k v -> AList k v
replaceAt k Nothing (AList m) = AList $ filter (\(k', _) -> k /= k') m
replaceAt k (Just v) (AList m) =
    case lookup k m of
      Nothing ->
          -- Not present in the list; add it
          AList ((k, v) : m)
      Just _ ->
          -- Present; replace it
          AList $ map (\(k', v') -> if k == k' then (k', v) else (k', v')) m

-- Just take the default implementation here.
instance Eq k => Ixed (AList k v)

instance Eq k => At (AList k v) where
    at k f (AList m) = fmap (\v' -> replaceAt k v' (AList m)) $ f (lookup k m)
© www.soinside.com 2019 - 2024. All rights reserved.