 <p>The difference is caused by <code>doSomeY</code> yielding a number in the first case vs. yielding a function in the second case when applied to one argument.</p> <p>Given</p> <pre><code>doSomeX x = if x==7 then True else False doSomeY x y = x+y+1 </code></pre> <p>we can infer the types (these aren't the most generic types possible, but they'll do for our purposes):</p> <pre><code>doSomeX :: Int -&gt; Bool doSomeY :: Int -&gt; Int -&gt; Int </code></pre> <p>Remember that <code>-&gt;</code> in type signature associates to the right, so the type of <code>doSomeY</code> is equivalent to</p> <pre><code>doSomeY :: Int -&gt; (Int -&gt; Int) </code></pre> <p>With this in mind, consider the type of <code>(.)</code>:</p> <pre><code>(.) :: (b -&gt; c) -&gt; (a -&gt; b) -&gt; a -&gt; c </code></pre> <p>If you define</p> <pre><code>doSomeXY = doSomeX.doSomeY </code></pre> <p>...which is equivalent to <code>(.) doSomeX doSomeY</code>, it means that the first argument to <code>(.)</code> is <code>doSomeX</code> and the second argument is <code>doSomeY</code>. Hence, the type <code>b -&gt; c</code> (the first argument to <code>(.)</code>) must match the type <code>Int -&gt; Bool</code> (the type of <code>doSomeX</code>). So</p> <pre><code>b ~ Int c ~ Bool </code></pre> <p>Hence,</p> <pre><code>(.) doSomeX :: (a -&gt; Int) -&gt; a -&gt; Bool </code></pre> <p>Now, applying this to <code>doSomeY</code> causes a type error. As mentioned above,</p> <pre><code>doSomeY :: Int -&gt; (Int -&gt; Int) </code></pre> <p>So when inferring a type for <code>(.) doSomeX doSomeY</code> the compiler has to unify <code>a -&gt; Int</code> (the first argument of <code>(.) doSomeX</code>) with <code>Int -&gt; (Int -&gt; Int)</code> (the type of <code>doSomeY</code>). <code>a</code> can be unified with <code>Int</code>, but the second half won't work. Hence the compiler barfs.</p>