上面说到的Lens类型,最早出现在2009年Twan van Laarhoven的一篇文章(CPS based functional references,详见http://www.twanvl.nl/blog/haskell/cps-functional-references。)中,当时他并没有把这个类型的函数叫作Lens,而且关注的重点是如何运用合适的函子类型f获得getter和setter。上一章介绍的两个函子Identity和Const a这时扮演了至关重要的角色。首先,定义我们希望得到的getter和setter:

view :: Lens Position Double -> Position -> Double
set :: Lens Position Double -> Double -> Position -> Position
over :: Lens Position Double -> (Double -> Double) -> Position -> Position

我们希望能够从透镜组中得到的一组函数分别如下。

 view xLens应该得到Position -> Double类型的函数,也就是从坐标中提取出横坐标的函数。

 set xLens应该得到Double -> Position -> Position类型的函数,也就是设置坐标中的横坐标,并返回新坐标的函数。

 over xLens应该得到(Double -> Double) -> Position -> Position类型的函数,这个函数接收一个针对横坐标的变换函数,并把变换作用在坐标中的横坐标上,返回新的坐标。

我们为什么如此确定透镜组xLens包含所有需要的信息呢?下面把刚刚的xLens改写一下:

xLens f p = fmap setter $ f $ getter p
  where
    setter :: Double -> Position
    setter x' = p { positionX = x' }

    getter :: Position -> Double
    getter = positionX

实际上,为了能够把函子类型从小类型外层移到大类型的外层,我们既用到了getter,又用到了setter。接下来,将要向你展示view、set和over这些函数,它们全都是Lens类型函数的一个特例。我们需要做的,只是选择合适的函子类型来从Lens中提取想要的函数即可。有趣的是,上面3个函数中最容易实现的,是看上去最复杂的over函数。

评论

本文目前还没有评论……

我要评论

需要登录后才能发言
登录未成功,请修改提交。

× 454
× 1756
× 2438
× 965
× 1
× 1
× 1208
× 0
× 1
× 0
× 2
× 1
× 3
× 4
× 2764
× 818
× 1109