<p>There are two abstractions used for things like this in Haskell, one usings <code>Arrow</code>s and the other <code>Applicative</code>s. Both can be broken down into smaller parts than those used in <code>base</code>.</p>

<hr>

<p>If you go in the <code>Arrow</code> direction and <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=0CB8QFjAA&amp;url=http%3A%2F%2Farxiv.org%2Fabs%2F1007.2885&amp;ei=52KRVaLWAoTwoASV44OYCA&amp;usg=AFQjCNF7TMVyJnsjsrNguJGMYjCIYaBXRw&amp;sig2=uB6vQrlIINYTTpim5p5CAA" rel="nofollow noreferrer">break down the capabilities of <code>Arrow</code>s into component pieces</a>, you'd have a separate class for those arrows that are able to lift arbitrary functions into the arrow.</p>

<pre><code>class ArrowArr a where
    arr :: (b -&gt; c) -&gt; a b c
</code></pre>

<p>This would be the opposite of <code>ArrowArr</code>, arrows where any arbitrary arrow can be dropped to a function.</p>

<pre><code>class ArrowFun a where
    ($) :: a b c -&gt; (b -&gt; c)
</code></pre>

<p>If you just split <code>arr</code> off of <code>Arrow</code> you are left with <a href="https://stackoverflow.com/a/27387931/414413">arrow like categories that can construct and deconstruct tuples</a>.</p>

<pre><code>class Category a =&gt; ArrowLike a where
    fst   :: a (b, d) b
    snd   :: a (d, b) b
    (&amp;&amp;&amp;) :: a b c -&gt; a b c' -&gt; a b (c,c')
</code></pre>

<hr>

<p>If you go in the <code>Applicative</code> direction this is a <a href="https://hackage.haskell.org/package/pointed-2.0.2/docs/Data-Copointed.html" rel="nofollow noreferrer"><code>Copointed</code></a> "<code>Applicative</code> without <code>pure</code>" (which goes by the name <a href="https://hackage.haskell.org/package/semigroupoids-5.0.0.2/docs/Data-Functor-Apply.html#t:Apply" rel="nofollow noreferrer"><code>Apply</code></a>). </p>

<pre><code>class Copointed p where Source
    copoint :: p a -&gt; a

class Functor f =&gt; Apply f where
  (&lt;.&gt;) :: f (a -&gt; b) -&gt; f a -&gt; f b
</code></pre>

<p>When you go this way you typically drop the <code>Category</code> for functions and instead have a type constructor <code>C a</code> representing values (including function values) constructed according to a certain set of rules.</p>
Generalising ($) like Control.Category generalises (.)
<p>I had a thought to generalise <code>($)</code> like <code>Control.Category</code> generalises <code>(.)</code>, and I've done so with the code at the end of this post (<a href="https://ideone.com/Uc1398" rel="noreferrer">also ideone</a>).</p>

<p>In this code I've created a class called <code>FunctionObject</code>. This class has a function <code>($)</code> with the following signature:</p>

<pre><code>($) :: f a b -&gt; a -&gt; b
</code></pre>

<p>Naturally I make <code>(-&gt;)</code> an instance of this class so <code>$</code> continues to work with ordinary functions.</p>

<p>But this allows you to make special functions that, for example, know their own inverse, as the example below shows.</p>

<p>I've concluded there's one of three possibilities:</p>

<ol>
<li>I'm the first to think of it.</li>
<li>Someone else has already done it and I'm reinventing the wheel.</li>
<li>It's a bad idea.</li>
</ol>

<p>Option 1 seems unlikely, and my searches on <a href="http://hayoo.fh-wedel.de/" rel="noreferrer">hayoo</a> 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.</p>

<pre><code>import Prelude hiding ((.), ($))
import Control.Category ((.), Category)

class FunctionObject f where
  ($) :: f a b -&gt; a -&gt; b

infixr 0 $

instance FunctionObject (-&gt;) where
  f $ x = f x

data InvertibleFunction a b = 
   InvertibleFunction (a -&gt; b) (b -&gt; 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) =&gt; n -&gt; InvertibleFunction n n
add n = InvertibleFunction (+n) (subtract n)

main = do
  print $ add 2 $ 5 -- 7
  print $ inverse (add 2) $ 5 -- 3
</code></pre>