Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a lens twice

I'm struggling with using the lens library for a particular problem. I'm trying to pass

  1. an updated data structure
  2. a lens focussed on part of that updated structure

to another function, g. I pass both the lens and the data structure because g needs some shared information from the data structure as well as a piece of information. (If it helps, the data structure contains information on a joint probability distribution, but g only works on either marginal and needs to know which marginal I'm looking at. The only difference between the two marginals is their mean with the rest of their definition being shared in the data structure).

My first attempt looked like this

f :: Functor f => Params -> ((Double -> f Double) -> Params -> f Params) -> a
f p l = g (l %~ upd $ p) l
  where upd = ...

g p x = go p p^.x

but that fails during compilation because f gets inferred as being Identity for the update and Const Double for the getter.

What's the best way to accomplish what I want to do? I can imagine being able to do one of the following:

  1. make a copy of the lens so that the type inference can be different in each case
  2. rather than passing the updated structure and the lens, I pass the original structure and a lens which returns a modified value (if I only want to update the part of the structure that the lens looks at).
  3. making a better design choice for my functions/data structure
  4. something completely different

Thanks for any help!

like image 620
dbeacham Avatar asked May 02 '14 08:05

dbeacham


People also ask

How many times can you use the same lenses?

Daily disposable contacts are typically soft, flexible ones you should only wear once before tossing, the FDA explains. Depending on the brand, you can use extended wear contact lenses safely for up to 30 days.

What happens if I use daily lenses more than once?

Wearing daily contacts more often than recommended can greatly increase the risk for eye infection and other eye-related issues. It is important to follow your doctor's instructions when replacing and reusing contacts in order to maintain your eye health.

Can we use one day lens again?

You can only wear daily disposable contacts for one day and you cannot use them more than once. Without exception, you should throw them out after removing them, whether it's at the end of the day or after only a few hours.


1 Answers

András Kovács answer shows how to achieve this with RankNTypes. If you wish to avoid RankNTypes, then you can use ALens and cloneLens:

f :: a -> ALens' a Int -> (Int, a)
f a l = (newvalue, a & cloneLens l .~ newvalue)
  where oldvalue = a^.cloneLens l
        newvalue = if oldvalue == 0 then 0 else oldvalue - 1

Control.Lens.Loupe provides operators and functions that work on ALens instead of Lens.

Note that in many cases, you should also be able to use <<%~, which is like %~ but also returns the old value, or <%~, which returns the new value:

f :: a -> LensLike' ((,) Int) a Int -> (Int, a)
f a l = a & l <%~ g
  where g oldvalue = if oldvalue == 0 then 0 else oldvalue - 1

This has the advantage that it can also work with Isos or sometimes also with Traversals (when the target type is a Monoid).

like image 81
bennofs Avatar answered Oct 12 '22 10:10

bennofs