Post: Practical Profunctor Lenses & Optics in PureScript

Optics and lenses are, in my opinion, one of PureScript’s killer features.

I remember @monoidmusician teaching me how to use them to deal with a horrible set of deeply-nested maps I’d set up and having one of those functional programming aha! moments. Since then I’ve found them used pervasively through production code at companies I’ve worked for, but not very much written about how to use them to solve practical problems in PureScript.

I’ve published a new article which details exactly that, walking through the most common types, functions, and constructors from the profunctor-lenses library.

If you haven’t used optics before, or if you’re still not as comfortable with them as you’d like, this article will help you become more adept using them to solve real problems in your code.

thomashoneyman.com/articles/practical-profunctor-lenses-optics/

I’d love to hear what you think!

If you learned something new, please consider sharing this with your colleagues, Twitter followers, or other folks who might find it interesting and useful, too.


Thank you to @colinwahl, @JordanMartinez, @goodacre.liam, @monoidmusician, and Vance Palacio for reviewing the draft.

22 Likes

Really nice article, thanks!

1 Like

@thomashoneyman I finally managed to go through this, and it’s such a lovely introduction to lenses and prisms and now I’m recommending it to friends and family :smile:

So thanks a lot for writing your posts (I also loved the React one) as you do, it’s easy to see you put great care in making things clear and understandable and with a nice learning curve :slight_smile:

2 Likes

Thank you! I’m glad to hear that, and I’m looking forward to demystifying more things that have stumped me in the past.

1 Like

Responding to the request at the end for other good resources.

2 Likes

An excellent article! I like your discussion of the conventions your prefer to use with traversals when they are affine or not. I wish the conventional names of everything in optics encoded the intended uses rather than sounding generic.

BTW, I think there’s a typo where ix should be index:

Given an index, creates a traversal for a structure s , indexed by type ix and focusing on type a .

1 Like

This is great @thomashoneyman

I read the article before on

 type NestedData =
  Maybe (Array { foo :: Tuple String (Either Int Boolean), bar :: String })

Where

_NestedInt :: Int -> Traversal' NestedData Int
_NestedInt index = _Just <<< ix index <<< _foo <<< _2 <<< _Left

getNestedInt :: Int -> NestedData -> Maybe Int
getNestedInt index = preview (_NestedInt index)

What would be the index used to get the Int? 0?

I am visualising the walk back process like walking back a tree from the leaves, if that makes sense?

Thanks! You’re right, and this is fixed.

The index refers to the array, and _NestedInt leaves the specific index up to you – if you wanted to get the Int out of the first record in the array you’d do:

_FirstNestedInt :: Traversal' NestedData Int
_FirstNestedInt = _NestedInt 0