6

Given the following from fp-course:

class Functor f where
  (<$>) ::
    (a -> b)
    -> f a
    -> f b

class Functor f => Extend f where
  (<<=) ::
    (f a -> b)
    -> f a
    -> f b

I defined <$$> as so:

(<$$>) ::
  Comonad f =>
  (a -> b)
  -> f a
  -> f b
(<$$>) f fa = f <$> fa

However, I'm interested to know if there's another way to implement <$$> without using <$>. Is there? If so, please show it!

Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384

1 Answers1

10

You need the extract method of Comonad; Extend isn't enough to get away without fmap.

(<$$>)
  :: Comonad f
  => (a -> b)
  -> f a
  -> f b
f <$$> w = f . extract <<= w

This is basically how liftW is implemented in Control.Comonad.

Note also that you need <<= (or extend); extract and duplicate aren't sufficient. The situation is similar to that of Bind and Monad; you can implement fmap using >>= and pure, but not using >>= alone and not using join and pure.

dfeuer
  • 48,079
  • 5
  • 63
  • 167
  • 1
    It might be worth it to also explain this metaphorically: If you want to edit every value inside of a structure-with-contexts independently with the same action (`fmap`/`(<$>)`), you can accomplish it by editing every value within its context (`extend`/`(<<=)`) and just ignoring the given context (`extract`). – HTNW Jan 23 '19 at 13:52