有人能向我解释一下函数式镜头吗?这是一个令人惊讶的难以通过谷歌搜索的主题,我没有取得任何进展。我知道的只是它们提供与面向对象编程中的get/set功能类似的功能。
有人能向我解释一下函数式镜头吗?这是一个令人惊讶的难以通过谷歌搜索的主题,我没有取得任何进展。我知道的只是它们提供与面向对象编程中的get/set功能类似的功能。
镜片由两个函数组成,一个是获取器(getter),另一个是设置器(setter):
data Lens a b = Lens { getter :: a -> b, setter :: b -> a -> a }
例如,我们可能会为一对中的第一个和第二个部分拥有镜头:fstLens :: Lens (a, b) a
fstLens = Lens fst $ \x (a, b) -> (x, b)
sndLens :: Lens (a, b) b
sndLens = Lens snd $ \x (a, b) -> (a, x)
镜头的真正方便之处在于它们可以组合使用:
compose :: Lens b c -> Lens a b -> Lens a c
compose f g = Lens (getter f . getter g) $
\c a -> setter g (setter f c (getter g a)) a
它们会自动转换为 State
转换:
lensGet :: MonadState s m => Lens s a -> m a
lensGet = gets . getter
lensSet :: MonadState s m => Lens s b -> b -> m ()
lensSet f = modify . setter f
lensMod :: MonadState s m => Lens s b -> (b -> b) -> m ()
lensMod f g = modify $ setter f =<< g . getter f
(+=) :: (MonadState s m, Num b) => Lens s b -> b -> m ()
f += x = lensMod f (+ x)
f
和 g
搞反了。 - Apocalisp请参考以下问题的答案:lenses, fclabels, data-accessor - 哪个库更适合结构访问和变异 - 它对于镜头有非常清晰的解释。
此外,Data.Lenses 和 fclabel 这两个库的文档提供了一些很好的使用示例。