Search code examples
haskellhaskell-lens

Why does Setter have Traversable constraint?


When you look at setting in lens-family-core package, you'll find that its type is Identical f => ((a -> b) -> s -> t) -> LensLike f s t a b, and Identical is defined as class (Traversable f, Applicative f) => Identical f.

I understand it needs Applicative and Identical as it uses pure and extract, but I'm not sure why it needs Traversable.

setting :: Identical f => ((a -> b) -> s -> t) -> LensLike f s t a b
setting sec f = pure . sec (extract . f)

I also found that Setter in lens package had Traversable constraint through Settable. So I guess a setter needs Traversable in general.

Why does a setter need Traversable in general?


Solution

  • Setters don't really need Traversable, but effectively you enforce having this constraint anyway because Identical / Settable are classes that only allows trivial instances. I.e., either Identity or something isomorphic to it, and all of these are obviously traversable as well.

    Notice you could always write

    idenTraverse :: (Identical t, Applicative g) => (a -> g b) -> t a -> g (t b)
    idenTraverse f = fmap pure . f . extract
    

    which is equivalent to the standard traverse. (Actually this needs only Functor g, incidentally.)

    Explicitly requiring the standard Traversable interface makes for a cleaner, more consistent hierarchy, without actually changing what you can or can't do with the setters.