In the code below, my question concerns the top-most function someFunc
(everything below is just to provide a complete example). I use a record-syntax getter and fmap
there. What's the lens way to implement 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 } )
Just replace _barnSize
by (^. barnSize)
or, equivalently, view barnSize
:
someFunc :: Farm -> IntMap Size
someFunc farm = view barnSize <$> farm ^. farmBarns
For a "100% lens" solution, you can use the mapped
setter. In this case, though, I don't think there is any real advantage in doing that.
someFunc :: Farm -> IntMap Size
someFunc farm = (mapped %~ view barnSize) (farm ^. farmBarns)
Another possible spelling involves using to
to combine everything in a single getter. That doesn't buy you much here either, but it might be somewhat convenient if you wanted to keep working with the IntMap
in lens style by chaining additional getters/folds/etc.
someFunc :: Farm -> IntMap Size
someFunc farm = farm ^. farmBarns . to (fmap (view barnSize))
There is a special purpose combinator that subsumes the to
/(^.)
combination above. It is called views
:
someFunc :: Farm -> IntMap Size
someFunc farm = views farmBarns (fmap (view barnSize)) farm