jackfirth / lens

A Racket package for creating and composing pure functional lenses
Other
74 stars 8 forks source link

Add seemingly missing (list-filtered-lens) function. #310

Closed rouanvd closed 5 months ago

rouanvd commented 5 months ago

I have been trying to implement some basic functionality using lenses on lists and I was looking for a (list-filtered-lens) function which looks like it should be a standard feature. Something like:

(define (list-filtered-lens keep?)
  (make-lens
    (lambda (lst)
      (for/list ([elem  (in-list lst)]
                 #:when (keep? elem))
        elem))
    (lambda (tgt nvw)
      (map (lambda (elem)
             (if (keep? elem)
               nvw
               elem))
           tgt))))

I was wondering if this was left out on purpose or is it possible to add it into the library as a standard function?

jackfirth commented 5 months ago

I don't think that implementation works. The setter is replacing every filtered value with nvw, but for consistency with the getter, it should accept a new list of values and replace each filtered value with a corresponding value from that list. Otherwise, (lens-set l v (lens-get l )) wouldn't be the identity function.

rouanvd commented 5 months ago

Ah, yes, you are right. I am trying to write the following with lenses: Visit every element in a list that matches a predicate and update a specific struct field using a function. Something like this:

(lens-transform (lens-thrush
                  (list-where (lambda (p) (and (starts-with? (person-name p) "R")
                                               (< (person-age p) 18))))
                  person-age-lens)
                (list (person "Rouan" 17))
                (lambda (age) (+ age 10)))

This seems like it is missing and it is something I do a lot in the programs I write.

jackfirth commented 5 months ago

It's missing because it's best to implement that as a traversal, not a lens. I never got around to adding optics other than lenses to this library. It would be a pretty big endeavor to add traversals.

rouanvd commented 5 months ago

Ah that makes sense. I really want this functionality so I will probably implement traversal on my own. It is too painful to update nested data structures with the basic facilities in Racket.

jackfirth commented 5 months ago

You might be interested in the experimental glass package I wrote when I wanted to play around with a different approach to lenses. It has a basic implementation of traversals. I wouldn't recommend actually using that package, but hopefully it gives you something to work off of.