我认为这是解决方案:
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]
这个想法是 aTraversal
是一个幺半群。正确的解决方案需要对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]