从镜头列表创建遍历

Create a traversal from a list of lenses

假设我们在数据结构 S a 上有一个镜头列表 [Lens' (S a) a]。我想用同样的方法修改数据结构中每个镜头的焦距

我可以这样做:

s :: S a
s = _ 


ls :: [Lens' (S a) a]
ls = [a, b, c]
a, b, c = _

f :: a -> a
f = _

s' :: S a
s' = s
      & a %~ f
      & b %~ f
      & c %~ f

没关系,但如果我有 10、100 个镜头怎么办?我想要一些东西 喜欢

s' :: S a
s' = s & ls ??? f

(???) :: *

我在哪里找不到运算符 (???)

或许也可以把ls转成遍历,直接用(%~),我 不知道。

你有什么想法吗?

第一个问题是:那个类型是非法的。正如该问题中所讨论的,要将镜头放入容器中,您需要具体化镜头。完成后,您可以通过应用 (%~ f) 将每个镜头变成一个函数,然后通过简单的折叠来组合这些函数。

你得到的不是一个镜头,也不是一个遍历,而只是一个S a -> S a类型的函数(和你从a %~ f得到的一样)。我发现 a discussion 为什么通常不可能按照您提到的您希望的方式将多个镜头、设置器或遍历组合成一个遍历。

这是我上面概述的想法的实现。

data S a = S {_x, _y :: a} deriving Show
makeLenses ''S

ls :: [ReifiedLens' (S (S Int)) Int]
ls = [Lens (x.x), Lens (y.y)]

overEach :: [ReifiedLens' s a] -> (a -> a) -> (s -> s)
overEach ls f s = foldr applySetter s ls
  where applySetter (Lens l) acc = acc & l %~ f

s :: S (S Int)
s = S (S 1 2) (S 3 4)

λ> s & overEach succ ls
S {_x = S {_x = 2, _y = 2}, _y = S {_x = 3, _y = 5}}
(???) :: [ReifiedLens' (s a) a] -> (a -> a) -> s a -> s a
reLenses ??? f = foldl (.) identity $ map ((%~ f) . runLens) reLenses

将镜头封装在 Lens 构造函数中以获得 ReifiedLens'