ekmett / adjunctions

Simple adjunctions
http://hackage.haskell.org/package/adjunctions
Other
44 stars 27 forks source link

Add withIndex helper function? #40

Closed ChrisPenner closed 5 years ago

ChrisPenner commented 7 years ago

Hey there; this is a nicely thought out and very elegant lib!

I've found the following functions useful:

withIndex :: (Eq (Rep f), Representable f) => Rep f -> (a -> a) -> f a -> f a
setIndex :: (Eq (Rep f), Representable f) => Rep f -> a -> f a -> f a

With the relatively inefficient implementations:

withIndex :: (Eq (Rep f), Representable f) => Rep f -> (a -> a) -> f a -> f a
withIndex ind g fa = tabulate $ \rep ->
      let existing = index fa rep
       in if rep == ind then g existing
          else existing

setIndex :: (Eq (Rep f), Representable f) => Rep f -> a -> f a -> f a
setIndex ind = withIndex ind . const

If these would be of interest to others I can write up a PR. Let me know what you think;

Icelandjack commented 7 years ago

Is this not a lens

_Rep :: (Representable r, Eq (Rep r)) => Rep r -> Lens' (r a) a 
_Rep rep f ra = do
  a <- f (index ra rep)

  return $ tabulate $ \case
    ((== rep) -> True) -> a
    rep'               -> index ra rep'

withIndex & setIndex can be defined in terms of it, _Rep can be added if it doesn't exist already

withIndex :: (Eq (Rep f), Representable f) => Rep f -> (a -> a) -> (f a -> f a)
withIndex rep = over (_Rep rep)

setIndex :: (Eq (Rep f), Representable f) => Rep f -> a -> (f a -> f a)
setIndex rep = set (_Rep rep)
Icelandjack commented 7 years ago

this seems exactly like what @treeowl proposes in #30

ChrisPenner commented 7 years ago

@Icelandjack Yup I'd be totally fine with either _Rep or IxSure being added. I can write my own lenses for Representable functor of course, but it'd be nice to at least have a unifying class like IxSure to put things. That said, all the general implementations of IxSure are extremely inefficient, so that kinda sucks.

ChrisPenner commented 5 years ago

I recently discovered that it's trivial to instance the *WithIndex typeclasses using helpers from this lib.

E.g.

instance FunctorWithIndex MyRepType MyRepresentableFunctor where
  imap = imapRep

instance FoldableWithIndex MyRepType MyRepresentableFunctor where
  ifoldMap = ifoldMapRep

instance TraversableWithIndex MyRepType MyRepresentableFunctor where
  itraverse = itraverseRep

Then the indexed lenses provide the functionality I want quite nicely; e.g. the index lens works great!