 <blockquote> <ol> <li>What is <code>mk</code> returning?</li> </ol> </blockquote> <p>Let's go through a much simpler example In the documentation of GHC.Generics first. To achieve a generic function <code>encode :: Generic a =&gt; a -&gt; [Bool]</code> that bit serialize every data type which has a Generic instance, they defined the type class below : </p> <pre><code>class Encode' rep where encode' :: rep p -&gt; [Bool] </code></pre> <p>By defining <code>Encode'</code> instances for every Rep type (M1, K1, etc.), they made the function work universally on every data types.</p> <p>In <a href="https://ocharles.org.uk/blog/posts/2014-04-26-constructing-generically.html" rel="nofollow">Building data constructors with GHC Generics</a>, the author's final goal is a generic function <code>make :: Generic a =&gt; TypeOfConstructor a</code>, so naively one may define:</p> <pre><code>class Mk rep where mk :: (? -&gt; p) -- what should '?' be? </code></pre> <p>And soon realize that it's impossible due to a few problems:</p> <ol> <li><code>-&gt;</code>, the function type in haskell only takes one argument at a time, so <code>mk</code> won't be able to return anything sensible if the constructor takes more than one argument.</li> <li>The number and type of the arguments are unclear: it's relative to the <code>rep</code> type in concern.</li> <li>It cannot be plain <code>p</code> as the result type. Without the <code>rep</code> context it's impossible to derive instances for <code>:*:</code> or <code>:+:</code>, and the function will no longer work on any nested data type.</li> </ol> <p>Issue 1 can be solved with Data.Functor.Compose. A function of type <code>a -&gt; b -&gt; c</code> can be encoded into <code>Compose ((-&gt;) a) ((-&gt;) b) c</code>, it can be further composed while keeps a whole lot of information about argument types. And by making it a type parameter of <code>Mk</code>, issue 2 is solved too:</p> <pre><code>class Functor f =&gt; Mk rep f | rep -&gt; f where mk :: f (rep p) </code></pre> <p>where <code>f</code> is generalization over <code>Compose f g</code> and <code>(-&gt;) a</code>, which contains type-level information to construct a <code>rep p</code>, i.e. everything before the final <code>-&gt;</code> in <code>a -&gt; b -&gt; c -&gt; ... -&gt; rep p</code>. </p> <blockquote> <ol start="2"> <li>I'm guessing <code>Compose</code> comes from <code>Data.Functor.Compose</code>, which means that when I do <code>fmap f x</code>, it does the <code>fmap</code> two levels deep into the composed functors. But I can't make sense of the nested <code>fmap</code>s inside the <code>Compose</code>. </li> </ol> </blockquote> <p>In the <code>Mk</code> instance of <code>:*:</code>:</p> <pre><code>instance (Mk l fl, Mk r fr) =&gt; Mk (l :*: r) (Compose fl fr) where mk = Compose (fmap (\l -&gt; fmap (\r -&gt; l :*: r) mk) mk) </code></pre> <p><code>fmap</code> changes only the inner-most type of a nested Compose, in this case changes the final result of a n-ary function. <code>mk</code> here is literally concatenating two argument lists <code>fl</code> and <code>fr</code>, putting their results into a product type, namely</p> <pre><code>f :: Compose ((-&gt;) a) ((-&gt;) b) (f r) g :: Compose ((-&gt;) c) ((-&gt;) d) (g r) mk f g :: Compose (Compose ((-&gt;) a) ((-&gt;) b)) (Compose ((-&gt;) c) ((-&gt;) d)) ((:*:) f g r) -- or unwrapped and simplified (a -&gt; b -&gt; r) -&gt; (c -&gt; d -&gt; r') -&gt; a -&gt; b -&gt; c -&gt; d -&gt; (r, r') </code></pre> <blockquote> <ol start="3"> <li>For the instance of <code>M1 i c f</code>, I thought it would just wrap the inner values in <code>M1</code>, so the need to <code>M1 &lt;$&gt; mk</code> or <code>fmap M1 mk</code> makes no sense to me.</li> </ol> </blockquote> <p>It does just wrap the inner values in <code>M1</code>, but it's unclear how long the argument list of the underlying <code>f</code> is. If it takes one argument then <code>mk</code> is a function, otherwise it's a Compose. <code>fmap</code> wraps the inner-most value of them both.</p>