Lens for first item in array inside a record?



root [2:08 PM]
Good morning, I’ve been trying to get my head around lenses for a while and I’ve run into a problem. I have a data structure type R = { id :: Int, speakers :: Array Speaker }, where type Speaker = { id :: Int, state :: State } and data State = Init | Active | Done. I want to write a lens-like thing that lets me get the first Speaker in the Array if it is Active and also lets me update it. How do I do that?

parsonsmatt [2:11 PM]
in Haskell the filtered traversal does what you want, but you have to be careful with that one, you can construct non-lawful things with it.

λ> preview (traverse . filtered (==3)) [1,2,3,4,5]
Just 3
λ> set (traverse . filtered (==3)) 6 [1,2,3,4,5]

so, is what you want a lens that focuses on, eg, { id: 3, speakers: [<<<{ id: 0, state: Active}>>>, ...] } – the first speaker if that speaker is Active, and nothing? Or the first speaker in the array that happens to be active, if there is one?

root [2:13 PM]
Just the first speaker if that speaker is Active or Nothing.

natefaubion [2:13 PM]
You would want a Traversal, not a Lens specifically

root [2:14 PM]
I first thought I wanted a Prism since I want 0 or 1 Speakers. But I might’ve gotten that wrong.

natefaubion [2:15 PM]
Well, you want a Lens for the speakers, you want a traversal for the first item in the array, then you want a traversal for if its active
composing all those together is a traversal

parsonsmatt [2:16 PM]
A Prism allows you to reconstruct the whole value with just the part. So I can say review _Left 3 and construct an Either Int String. But I can’t say review yourThing aSpeaker and reconstruct the R and the rest of the array of speakers.

monoidmusician [2:16 PM]
try ix 0 (;

root [2:18 PM]
@parsonsmatt That’s true. Thank you for clarifying that.
Thank you all for the help! I now know how to continue!