在下面的代码中,我的问题涉及最顶层的函数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 } )
答案 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并将其用于左手的结果。