Suppose I have the following:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Book = Book {
_author :: String,
_title :: String
} deriving (Show)
makeLenses ''Book
data Location = Location {
_city :: String,
_state :: String
} deriving (Show)
makeLenses ''Location
data Library = Library {
_location :: Location,
_books :: [Book]
} deriving (Show)
makeLenses ''Library
lib :: Library
lib = Library (Location "Baltimore" "MD") [Book "Plato" "Republic", Book "Aristotle" "Ethics"]
I'm trying to understand various ways of reaching down through multiple layers by composing lenses. I know how to do these operations:
-- returns "Baltimore"
lib ^. location . city
-- returns a copy of lib with the city replaced
set (location . city) "Silver Spring" lib
But what if I want to change book titles? Maybe I want to change them all using map
, or I just want to change the third one using !! 2
? It seems I should make a new lens for that. I think I should compose the books
and title
lenses with an intermediate function, namely map
or !!
.
books . (!! 2) . title
-- or
books . map . title
How would I go about that?
muhmuhten is correct you should read about traversals in the lens package.
> over (books . traverse . title) (++" hi") lib
Library {_location = Location {_city = "Baltimore", _state = "MD"}, _books = [Book {_author = "Plato", _title = "Republic hi"},Book {_author = "Aristotle", _title = "Ethics hi"}]}
traverse
allows you to deal with every element in a list. If you want to effect one element of a list then you use element
which takes an Int
to indicate the index dealt with.
> over (books . element 0 . title) (++" hi") lib
Library {_location = Location {_city = "Baltimore", _state = "MD"}, _books = [Book {_author = "Plato", _title = "Republic hi"},Book {_author = "Aristotle", _title = "Ethics"}]}
Hope that helps.
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