Подтвердить что ты не робот

Получение нескольких результатов с карты с помощью "объектива"

Импорт:

> import Control.Lens
Control.Lens> import qualified Data.Map as Map

и значение карты, определяемое следующим образом:

Control.Lens Map> let m = Map.fromList [('a', 1), ('c', 3), ('b', 2)]

Я могу получить элементы один за другим так:

Control.Lens Map> view (at 'b') m
Just 2

Я хочу знать, есть набор ключей, таких как:

Control.Lens Map> import qualified Data.Set as Set
Control.Lens Map Set> let keys = Set.fromList ['d', 'c', 'b']

как построить такой getter (я думаю), используя который я смогу получить набор (или список) соответствующих элементов:

Control.Lens Map Set> view (**???**) m
[3, 2]

Обратите внимание, что результат содержит только 2 элемента, потому что нет соответствия для ключа 'd'.

4b9b3361

Ответ 1

Следующие действия будут работать, если вы хотите, чтобы получатель получал только несколько полей.

Сначала вам нужно сделать Accessor из объектива экземпляром Monoid (этот экземпляр находится в в HEAD, но еще не выпущен , уже определенный в lens >= 4, поэтому вам нужно только определить экземпляр, если вы работаете со старой версией библиотеки).

import Data.Monoid
import Control.Lens

instance Monoid r => Monoid (Accessor r a) where
  mempty = Accessor mempty
  mappend (Accessor a) (Accessor b) = Accessor $ a <> b

Затем вы можете использовать этот экземпляр для объединения нескольких объективов/обходов в один обход:

>>> import qualified Data.Set as S
>>> import qualified Data.Map as M
>>> import Data.Foldable (foldMap)
>>> import Control.Lens
>>> let m = M.fromList [('a',1), ('b',2), ('c',3)]
>>> let k = S.fromList ['b','c','e']
>>> m ^.. foldMap at k
[Just 2,Just 3,Nothing]
>>> m ^.. foldMap ix k
[2,3]

foldMap использует экземпляр Monoid для Accessor и экземпляр Monoid для функций.

Ответ 2

Я думаю, что это решение:

import Control.Applicative
import Control.Lens
import qualified Data.Map as M
import Data.Monoid hiding ((<>))

empty :: (Applicative f, Monoid a) => (b -> f b) -> (a -> f a)
empty _ _ = pure mempty

(<>)
    :: (Applicative f, Monoid a)
    => ((b -> f b) -> (a -> f a))
    -> ((b -> f b) -> (a -> f a))
    -> ((b -> f b) -> (a -> f a))
(l1 <> l2) f a = mappend <$> (l1 f a) <*> (l2 f a)

Пример:

>>> toListOf (at "A" <> at "B" <> at "C") (M.fromList [("A", 1), ("B", 2)])
[Just 1, Just 2, Nothing]

Идея состоит в том, что a Traversal является моноидом. Для правильного решения потребуется newtyping Traversal.

Изменить: Вот правильный экземпляр Monoid со всеми новыми файлами:

import Control.Applicative
import Control.Lens
import qualified Data.Map as M
import Data.Monoid
import Data.Foldable

newtype Combinable f a b = Combinable { useAll :: (b -> f b) -> (a -> f a) }

instance (Applicative f, Monoid a) => Monoid (Combinable f a b) where
    mempty = Combinable (\_ _ -> pure mempty)
    mappend (Combinable l1) (Combinable l2)
        = Combinable (\f a -> mappend <$> (l1 f a) <*> (l2 f a))

myMap :: M.Map String Int
myMap = M.fromList [("A", 1), ("B", 2)]

myLens :: Traversal' (M.Map String Int) (Maybe Int)
myLens = useAll $ foldMap (Combinable . at) ["A", "B", "C"]

Пример:

>>> toListOf myLens myMap
[Just 1,Just 2, Nothing]