Dealing with invertible functions

I was trying to think of a way to deal with invertible functions, say if I want to set up a one-to-one mapping from A<->B without having to maintain two sets of functions (and worry about them getting out of sync). So I thought about making an "invertible" function. This is a function that knows it's own inverse, and you can compose them and get the inverses for free. Of course you need to set up the base functions manually, but then after that the composed functions don't have to be maintained separately both ways. Below I'm going to include some code, and I have a few questions: 1) Am I (badly) reinventing the wheel. 2) Is there otherwise something terrible with this approach. 3) I ended up wanting a function with signature "f a b -> a -> b". This feels strangly like applicative but not exactly. Am I reinventing the wheel here also or should I be doing this differently? Any advise appreciated, the ideone link is here: https://ideone.com/HlUHUd But I've also copied the code below: --- import Prelude hiding ((.)) import Control.Category ((.), (<<<), (>>>), Category) data InvertibleFunction a b = InvertibleFunction (a -> b) (b -> a) instance Category InvertibleFunction where (InvertibleFunction b_c c_b) . (InvertibleFunction a_b b_a) = InvertibleFunction (b_c . a_b) (b_a . c_b) inv (InvertibleFunction x y) = InvertibleFunction y x add :: (Num n) => n -> InvertibleFunction n n add x = InvertibleFunction (+x) (\y -> y - x) class KindaApplicative f where (<$>) :: f a b -> a -> b instance KindaApplicative InvertibleFunction where (InvertibleFunction f _) <$> x = f x main = print $ ((inv (add 2)) <$> 5)

Look at Control.Lens.Iso
Clinton Mead
I was trying to think of a way to deal with invertible functions, say if I want to set up a one-to-one mapping from A<->B without having to maintain two sets of functions (and worry about them getting out of sync).
So I thought about making an "invertible" function. This is a function that knows it's own inverse, and you can compose them and get the inverses for free. Of course you need to set up the base functions manually, but then after that the composed functions don't have to be maintained separately both ways.
Below I'm going to include some code, and I have a few questions:
1) Am I (badly) reinventing the wheel. 2) Is there otherwise something terrible with this approach. 3) I ended up wanting a function with signature "f a b -> a -> b". This feels strangly like applicative but not exactly. Am I reinventing the wheel here also or should I be doing this differently?
Any advise appreciated, the ideone link is here: https://ideone.com/HlUHUd But I've also copied the code below:
---
import Prelude hiding ((.)) import Control.Category ((.), (<<<), (>>>), Category)
data InvertibleFunction a b = InvertibleFunction (a -> b) (b -> a)
instance Category InvertibleFunction where (InvertibleFunction b_c c_b) . (InvertibleFunction a_b b_a) = InvertibleFunction (b_c . a_b) (b_a . c_b)
inv (InvertibleFunction x y) = InvertibleFunction y x
add :: (Num n) => n -> InvertibleFunction n n add x = InvertibleFunction (+x) (\y -> y - x)
class KindaApplicative f where (<$>) :: f a b -> a -> b
instance KindaApplicative InvertibleFunction where (InvertibleFunction f _) <$> x = f x main = print $ ((inv (add 2)) <$> 5)

Le lundi 29 juin 2015 11:19:57 UTC+3, Clinton Mead a écrit :
I was trying to think of a way to deal with invertible functions, say if I want to set up a one-to-one mapping from A<->B without having to maintain two sets of functions (and worry about them getting out of sync).
So I thought about making an "invertible" function. This is a function that knows it's own inverse, and you can compose them and get the inverses for free. Of course you need to set up the base functions manually, but then after that the composed functions don't have to be maintained separately both ways.
Below I'm going to include some code, and I have a few questions:
1) Am I (badly) reinventing the wheel.
3) I ended up wanting a function with signature "f a b -> a -> b". This feels strangly like applicative but not exactly. Am I reinventing the wheel here also or should I be doing this differently?
Perhaps, there is an analogue of your function application (for bijections, <$>) in Arrow, which is a class of Data.Bijection.Bijection. Probably not in Category though. (I've just stumbled upon a similar discussion at http://programmers.stackexchange.com/a/215503/11591 ; with similar requirements: "There's a common reason why I can't use Applicative or Arrow (or Monad) - I can't wrap a normal function (in general) because values of my type *represent* a function but are *represented* by data, and won't support arbitrary functions if if there was a way to translate." You, too, can't inject an arbitrary function because you have to manually write
Perhaps http://hackage.haskell.org/package/TypeCompose-0.9.10/docs/Data-Bijection.ht...: 2) Is there otherwise something terrible with this approach. the inverse.) class KindaApplicative f where
(<$>) :: f a b -> a -> b
instance KindaApplicative InvertibleFunction where (InvertibleFunction f _) <$> x = f x
Best wishes, Ivan Z.
participants (3)
-
Antonio Nikishaev
-
Clinton Mead
-
Ivan Zakharyaschev