Search code examples
haskelltraversalfunctorhaskell-lens

In the lets-lens tutorial, how do you refactor out the call to traverse in order to implement over?


In the exercises I have implemented fmapT:

-- Let's remind ourselves of Traversable, noting Foldable and Functor.
--
-- class (Foldable t, Functor t) => Traversable t where
--   traverse ::
--     Applicative f => 
--     (a -> f b)
--     -> t a
--     -> f (t b)

-- | Observe that @fmap@ can be recovered from @traverse@ using @Identity@.
--
-- /Reminder:/ fmap :: Functor t => (a -> b) -> t a -> t b
fmapT ::
  Traversable t =>
  (a -> b)
  -> t a
  -> t b
fmapT =
  error "todo: fmapT"

Now how do I implement over?

-- | Let's refactor out the call to @traverse@ as an argument to @fmapT@.

over ::
  ((a -> Identity b) -> s -> Identity t)
  -> (a -> b)
  -> s
  -> t
over = error "undefined"

Solution

  • You can implement fmapT using traverse as:

    fmapT f s = runIdentity (traverse (Identity . f) s)
    

    now the next exercise is to refactor this function by providing traverse as a parameter rather than hard-coding it in the definition. If you choose Identity as the applicative type constructor then the type of traverse is:

    (Traversable t) => (a -> Identity b) -> t a -> Identity (t b)
    

    if you provide this as a parameter to fmapT you end up with something like over:

    over' :: Traversable t => ((a -> Identity b) -> t a -> Identity (t b)) -> (a -> b) -> t a -> t b
    over' l f s = runIdentity (l (Identity . f) s)
    

    since the Traversable constraint exists in traverse it is not required by over' which has the more general type of over given in the exercise i.e.

    over :: ((a -> Identity b) -> (s -> Identity t)) -> (a -> b) -> s -> t
    

    and

    over' =  over traverse