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
You can use mapped
(or traversed
) to 'map' over a traversable using lenses, in your case:
someFunc :: Farm -> IntMap Size
someFunc farm =
farm ^. farmBarns & mapped %~ view barnSize
This may be a bit confusing, but here's what's happening, I'll add brackets to make it a little clearer
someFunc :: Farm -> IntMap Size
someFunc farm =
(farm ^. farmBarns) & (mapped %~ (view barnSize))
So basically, we use farm ^. farmBarns
to get the IntMap Barns
from the farm, on the right hand side of &
we construct a setter using %~
which is the infix of over
, however the function which over
passes its target to is actually just focuses a the barnSize using a lens. view barnSize :: Barn -> Size
.
Lastly we use &
to tie it all together which is equivalent to flip $
and takes the setter from the right hand and uses it on the result of the left hand.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With