yong
yong

Reputation: 3633

Use Lens as `map`

I want to convert this line of code map (^?! ix 0) [[0, 1], [4, 5], [9, 1]] to entirely use lenses, so something like [[0, 1], [4, 5], [9, 1]] & each . ix 0. However, the types don't match up. What is the correct way to do this?

Upvotes: 8

Views: 343

Answers (2)

danidiaz
danidiaz

Reputation: 27756

Use folded:

Prelude Control.Lens> [[0, 1], [4, 5], [9, 1]] ^.. folded . ix 0
[0,4,9]

Works on any Foldable.

Also, if you plan to always extract the first element, perhaps it would be clearer to use the _head traversal from Control.Lens.Cons instead of ix.

[[0, 1], [4, 5], [9, 1]] ^.. folded . _head

Upvotes: 10

Ørjan Johansen
Ørjan Johansen

Reputation: 18189

You can use either of

Prelude Control.Lens> [[0, 1], [4, 5], [9, 1]] & each %~ (^?! ix 0)
[0,4,9]
Prelude Control.Lens> [[0, 1], [4, 5], [9, 1]] ^.. each . ix 0
[0,4,9]

The first corresponds to precisely what you wrote, using the unsafe (^?!) operator, which means that it can give an error. The second is safer by leaving out empty lists.

They work in somewhat different ways: The first creates a modified version of your original structure, which corresponds more to what map does, and it can be used on structures that aren't lists.

The second creates a list summary of your structure using the lens fold provided; although it can be used with many kinds of structures, the result is always a list.

You can also replace each by traverse (or, as @danidiaz points out, the slightly more general traversed) in this. The former works for many special things like tuples, while the latter works for any Traversable.

Upvotes: 10

Related Questions