title: How to write gcast for type families?
body: <p>I'm trying to write a variant of <code>Data.Typeable.gcast</code> which works for type families of kind <code>* -&gt; *</code>.  What I'm looking for is:</p>
  
  <pre><code>{-# LANGUAGE TypeFamilies #-}
  import Data.Typeable
  
  type family T
  
  gcastT :: (Typeable a,Typeable b) =&gt; T a -&gt; Maybe (T b)
  gcastT = undefined -- but that's not working too well!
  </code></pre>
  
  <p>going by analogy to <code>gcast :: (Typeable a,Typeable b) =&gt; f a -&gt; Maybe (f b)</code>.</p>
  
  <p>Is this possible? </p>
  
  <p>I <em>could</em> change the context to <code>(Typeable (T a),Typeable (T b)) =&gt;</code> but I'd prefer this signature for aesthetic reasons: <code>gcast</code> doesn't need <code>Typeable1 f</code>, after all.</p>
  
  <hr>
  
  <p>Some background in case I'm solving the wrong problem for what I actually want to achieve: my goal is to write a function <code>matchAndExtract</code>:</p>
  
  <pre><code>matchAndExtract :: (Eq a, Typeable a, Eq b, Typeable b) =&gt; a -&gt; b -&gt; T b -&gt; Maybe (T a)
  matchAndExtract x k v = if (cast x == Just k) then gcastT v else Nothing
  </code></pre>
  
  <p>which checks <code>x</code> and <code>k</code> for being of the same type and being equal, and then returning the supplied <code>T b</code> (which we by then know to be the same as <code>T a</code> - T might not be injective, but it <em>is</em> a function!) or <code>Nothing</code>, otherwise.</p>
  
  <p>I've got a work-around by wrapping the offending <code>T a</code> in a <code>newtype</code>, using <code>gcast</code>, and unwrapping again:</p>
  
  <pre><code>matchAndExtractF :: (Eq a, Typeable a, Eq b, Typeable b) =&gt; a -&gt; b -&gt; f b -&gt; Maybe (f a)
  matchAndExtractF x k v = if (cast x == Just k) then gcast v else Nothing
  
  newtype WrapT a = WrapT { unWrapT :: T a }
  
  matchAndExtractViaWrap :: (Eq a, Typeable a, Eq b, Typeable b) =&gt; a -&gt; b -&gt; T b -&gt; Maybe (T a)
  matchAndExtractViaWrap x k v = fmap unWrapT $ matchAndExtractF a k (WrapT v)
  </code></pre>
  
  <p>but that just rubs me the wrong way! This also works for instances for which <code>T a</code> is not an instance of <code>Typeable</code>; that again seems to me to indicate the <code>Typeable (T a)</code> contexts shouldn't be needed.</p>
  
  <p>The work-around is perfectly acceptable, but I'd like to get rid of the spurious <code>WrapT</code> type.</p>