I had a thought to generalise ($)
like Control.Category
generalises (.)
, and I've done so with the code at the end of this post (also ideone).
In this code I've created a class called FunctionObject
. This class has a function ($)
with the following signature:
($) :: f a b -> a -> b
Naturally I make (->)
an instance of this class so $
continues to work with ordinary functions.
But this allows you to make special functions that, for example, know their own inverse, as the example below shows.
I've concluded there's one of three possibilities:
Option 1 seems unlikely, and my searches on hayoo didn't reveal option 2, so I suspect option 3 is most likely, but if someone could explain why that is it would be good.
import Prelude hiding ((.), ($))
import Control.Category ((.), Category)
class FunctionObject f where
($) :: f a b -> a -> b
infixr 0 $
instance FunctionObject (->) where
f $ x = f x
data InvertibleFunction a b =
InvertibleFunction (a -> b) (b -> a)
instance Category InvertibleFunction where
(InvertibleFunction f f') . (InvertibleFunction g g') =
InvertibleFunction (f . g) (g' . f')
instance FunctionObject InvertibleFunction where
(InvertibleFunction f _) $ x = f $ x
inverse (InvertibleFunction f f') = InvertibleFunction f' f
add :: (Num n) => n -> InvertibleFunction n n
add n = InvertibleFunction (+n) (subtract n)
main = do
print $ add 2 $ 5 -- 7
print $ inverse (add 2) $ 5 -- 3
There are two abstractions used for things like this in Haskell, one usings Arrow
s and the other Applicative
s. Both can be broken down into smaller parts than those used in base
.
If you go in the Arrow
direction and break down the capabilities of Arrow
s into component pieces, you'd have a separate class for those arrows that are able to lift arbitrary functions into the arrow.
class ArrowArr a where
arr :: (b -> c) -> a b c
This would be the opposite of ArrowArr
, arrows where any arbitrary arrow can be dropped to a function.
class ArrowFun a where
($) :: a b c -> (b -> c)
If you just split arr
off of Arrow
you are left with arrow like categories that can construct and deconstruct tuples.
class Category a => ArrowLike a where
fst :: a (b, d) b
snd :: a (d, b) b
(&&&) :: a b c -> a b c' -> a b (c,c')
If you go in the Applicative
direction this is a Copointed
"Applicative
without pure
" (which goes by the name Apply
).
class Copointed p where Source
copoint :: p a -> a
class Functor f => Apply f where
(<.>) :: f (a -> b) -> f a -> f b
When you go this way you typically drop the Category
for functions and instead have a type constructor C a
representing values (including function values) constructed according to a certain set of rules.