Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function to automatically unwrap / rewrap values in haskell?

Tags:

haskell

I made a function as follows:

pen :: (a -> b) -> (b -> a) -> (b -> b) -> a -> a
pen conv rev app = rev . app . conv

which is used as follows:

pen read show (\x -> x + 1) "5"
"6"

I am quite new to Haskell, and I am wondering if a function like this exists in the Haskell standard library and what it is called, as I can't find it on Hoogle.

I'm also assuming there is some way to achieve this without (a -> b) -> (b -> a) -> ... and just having a single bijective function, but I'm also not sure how to do this.

Cheers!

like image 346
insou Avatar asked Jan 01 '23 04:01

insou


1 Answers

I think the most standard name for a general version of this function is dimap. It doesn't show up in a Hoogle search, unfortunately, since Hoogle lacks support for instances involving (->).

Anyway, dimap is a type class method (for the Profunctor class), so it's more general than what you want (the same way fmap would be more general than what someone looking for map actually wants). Specialized to the Profunctor instance for functions, it's still more general than you want, as it allows an arbitrary transformation of its input and output arguments to any types, so its type signature specialized to functions is:

dimap :: (a -> b) -> (c -> d) -> (b -> c) -> (a -> d)

which can obviously be be further specialized to the function pen that you want:

dimap :: (a -> b) -> (b -> a) -> (b -> b) -> (a -> a)

It's not in base, but it's included in the lens package or in the standalone profunctors package:

> import Data.Profunctor   -- from "profunctors"
> dimap read show (\x -> x + 1) "5"
"6"

Haskell functions of type a -> b can't be "bijective" obviously, but if you use the lens package, an Iso represents a bijective function.

You can define an Iso from a function and its inverse by writing:

> import Control.Lens
> showRead = iso show read

To apply a function using this Iso as a wrapper/unwrapper, you can use the Lens function under:

> under showRead (+1) "5"
"6"

I guess it's worth noting that showRead maybe isn't a great Iso (i.e., isn't fully law-abiding), since show and read aren't perfect inverses. (That is, some show instances produce values that can't be read back to reproduce the value.)

like image 200
K. A. Buhr Avatar answered May 29 '23 16:05

K. A. Buhr