使用Haskell的镜头库来镜像镜头

时间:2016-11-14 14:27:26

标签: haskell lens

在下面的代码中,我的问题涉及最顶层的函数someFunc(以下所有内容仅用于提供完整的示例)。我在那里使用记录语法getter和fmap。实施someFunc的镜头方式是什么?

import           Control.Lens
import           Data.IntMap  (IntMap)

someFunc :: Farm -> IntMap Size
someFunc farm =
  _barnSize <$> farm ^. farmBarns

data Farm = Farm
  { _farmBarns :: IntMap Barn
  }

farmBarns :: Lens' Farm (IntMap Barn)
farmBarns = lens _farmBarns (\farm barns -> farm { _farmBarns = barns } )

type Size = (Int, Int)

data Barn = Barn
  { _barnSize :: Size
  }

barnSize :: Lens' Barn Size
barnSize = lens _barnSize (\barn size -> barn { _barnSize = size } )

2 个答案:

答案 0 :(得分:6)

只需将AppDelegate替换为_barnSize或等同于(^. barnSize)

view barnSize

对于&#34; 100%镜头&#34;解决方案,您可以使用mapped setter。不过,在这种情况下,我认为这样做没有任何实际优势。

someFunc :: Farm -> IntMap Size
someFunc farm = view barnSize <$> farm ^. farmBarns

另一种可能的拼写方法是使用someFunc :: Farm -> IntMap Size someFunc farm = (mapped %~ view barnSize) (farm ^. farmBarns) 将所有内容组合在一个getter中。这对你来说也不算什么,但如果你想通过链接额外的getters / folds /等继续使用 lens 风格的to,这可能会有点方便。

IntMap

有一个特殊用途的组合子,它包含上面的someFunc :: Farm -> IntMap Size someFunc farm = farm ^. farmBarns . to (fmap (view barnSize)) / to组合。它被称为views

(^.)

答案 1 :(得分:2)

您可以使用mapped(或traversed)来映射&#39;在你的情况下,穿过可穿戴的镜片:

someFunc :: Farm -> IntMap Size
someFunc farm =
    farm ^. farmBarns & mapped %~ view barnSize

这可能有点令人困惑,但在这里发生了什么,我会添加括号以使其更清晰

someFunc :: Farm -> IntMap Size
someFunc farm =
    (farm ^. farmBarns) & (mapped %~ (view barnSize))

基本上,我们使用farm ^. farmBarns从服务器场获取IntMap Barns,在&的右侧,我们使用%~构建一个setter,这是一个中缀over的{​​{1}},over通过其目标的功能实际上只是使用镜头聚焦barnSize。 view barnSize :: Barn -> Size

最后,我们使用&将所有内容绑定在一起,相当于flip $,并从右手拿出setter并将其用于左手的结果。