Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composing lenses with Control.Lens where an intermediate function must be called

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?

like image 534
rlkw1024 Avatar asked Feb 15 '23 09:02

rlkw1024


1 Answers

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.

like image 50
Davorak Avatar answered May 17 '23 12:05

Davorak