Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Isomorphic `fmap` in Haskell

Does such a thing exist in Haskell's Prelude?

wfmap :: Functor f
      => a
      -> (a -> b)
      -> (b -> a)
      -> (b -> f b)
      -> f a
wfmap x u w g = fmap (w) (g (u x))

In a project I'm working on, I often found myself 'converting' a type to another, process it and 'converting' it back.

like image 539
iluvAS Avatar asked Dec 03 '16 12:12

iluvAS


1 Answers

Reordering the arguments, as leftaroundabout suggests, allows for a tidier definition:

wfmap :: Functor f => (a -> b) -> (b -> a) -> (b -> f b) -> a -> f a
wfmap u w g = fmap w . g . u

As for library support, lens provides nifty support for isomorphisms. A bit more broadly, as Gurkenglas notes...

Functor f => (b -> f b) -> a -> f a is also called Lens' a b and is the centerpiece of the lens library.

Without diving into the details of how and why that works, one consequence is that your function might be defined as:

wfmap :: Functor f => (a -> b) -> (b -> a) -> (b -> f b) -> a -> f a
wfmap u w g = (iso u w) g

Or even:

wfmap :: Functor f => (a -> b) -> (b -> a) -> (b -> f b) -> a -> f a
wfmap = iso

wfmap is just (a specialised version of) iso, which gives out a function which can be used to convert an b -> f b function on the isomorphism "destination" to an a -> f a one on the isomorphism "source".

It is also worth mentioning mapping, which can be used for the somewhat different purpose of applying fmap on the other side of an isomorphism:

GHCi> :t \u w g -> over (mapping (iso u w)) (fmap g)
\u w g -> over (mapping (iso u w)) (fmap g)
  :: Functor f => (s -> a) -> (b -> t) -> (a -> b) -> f s -> f t
GHCi> :t \u w g -> under (mapping (iso u w)) (fmap g)
\u w g -> under (mapping (iso u w)) (fmap g)
  :: Functor f => (s -> a) -> (b -> a1) -> (a1 -> s) -> f b -> f a

Finally, note that iso u w can be replaced by any Iso you might find in the libraries or have predefined elsewhere.

like image 199
duplode Avatar answered Sep 19 '22 19:09

duplode