<div>Roger,</div><div><br></div>I have only the first edition at hand so I don&#39;t have the big picture of what&#39;s going on. My guess is that based on the year of publication (1998) of the 2nd edition, Bird was writing at a time when the Num typeclass hierarchy was still in flux and simply wasn&#39;t what it is today.<div>

<br></div><div>Some comments:</div><div><br></div><div>&gt; The type of 0 is ambiguous, it could be an Integer or it could be a Double. This ambiguity can be seen by checking its type using WinGHCi:<br><br>&gt; :type 0<br>

&gt; 0 :: Num a =&gt; a&quot;</div><div><br></div><div>Rather than ambiguous, it&#39;s better to say that 0 is polymorphic. Or that it&#39;s a Num-constrained expression. The definitive meaning of ambiguous is whatever the type checker reports as such. ;)</div>

<div><br></div><div>&gt; The datatype Double falls within the class Fractional.</div><div><br></div><div>Better to say: there is an instance of Double for the class Fractional. The idea of &quot;falling&quot; suggests it&#39;s all forced upon the language by the Powers That Be. It&#39;s not. There&#39;s a declaration for the instance in the prelude. And the prelude can be suppressed.</div>

<div><br></div><div>&gt; Fundamental rule of Haskell: you cannot compare an Integer against a Double, you can only compare a Double against a Double.</div><div><br></div><div>You didn&#39;t quite ask it this way, but let me treat it as a question: Is it possible to create a typeclass with a method compare that takes 2 independently varying types? You&#39;re correct: No, it can&#39;t be done if you restrict yourself to Haskell98. However, multi-parameter typeclasses are extremely well-supported and widely used both depth- (historically) and breadth-wise (non-GHC). </div>

<div><br></div><div>&gt; Here is the signature for floor:</div><div><div>&gt; floor :: (Fractional a, Ord a, Real c) =&gt; a -&gt; c<br>&gt; Read as: Invoke function floor with a Fractional (Double) value and it will return a Real (Integer) value.</div>

<div><br></div><div>Better to read as &quot;floor takes a Fractional and Ord-constrained input and produces a Real-constrained output.&quot; Why does this help Haskell learners? Because writing the following is plenty common:</div>

<div><br></div><div>floor :: Fractional a -&gt; Real c</div><div>or</div><div>sequence :: [Monad a] -&gt; Monad [a]</div><div><br></div><div>Must. Keep. Types. And. Type classes. Distinct.</div><div><br></div><div>That said, awareness of the importance of speaking out code is a strong sign of success in learning the language. In due course those combinator-laden expressions won&#39;t seem such a dense fog of arcane symbols.</div>

<div><br></div><div>Really impressed at your making notes and publishing them. I look forward to more of your tutorials!</div><div><div><div><br></div><div><br clear="all">-- Kim-Ee<br>
<br><br><div class="gmail_quote">On Sun, Nov 4, 2012 at 4:40 PM, Costello, Roger L. <span dir="ltr">&lt;<a href="mailto:costello@mitre.org" target="_blank">costello@mitre.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

Hi Folks,<br>
<br>
On page 82 of the book &quot;Introduction to Functional Programming using Haskell&quot; the author Richard Bird provides this sample implementation of the floor function:<br>
<br>
floor x  =  searchFrom 0<br>
                where   searchFrom      =  decrease . upper . lower<br>
                                lower                   =  until (&lt;=x) decrease<br>
                                upper                   =  until (&gt;x) increase<br>
                                decrease n      =  n - 1<br>
                                increase n      =  n + 1<br>
<br>
The problem with that implementation is that it does not return an Integer value; rather, it returns a decimal (Double) value. Here&#39;s an example:<br>
<br>
        floor (-3.4)    -- returns (-4.0)<br>
<br>
That is wrong. The specification for floor says that it &quot;maps a value of type Float to a value of type Integer.&quot; Clearly it is not producing an Integer result.<br>
<br>
I will now explain how to revise floor so that it returns an Integer value. In the process we will see an excellent illustration of the Haskell types.<br>
<br>
The heart of the problem is with the until function.<br>
<br>
Here is how Richard Bird implements it:<br>
<br>
until           ::  (a -&gt; Bool) -&gt; (a -&gt; a) -&gt; a -&gt; a<br>
until p f y     =  if p y then y else until p f (f y)<br>
<br>
It takes three arguments, p, f, and y. Look at the signature of that function. The type of the third argument, y, dictates the type of the other arguments and the type of the result--whatever type y is, the other arguments must be the same type and the result must be the same type.<br>


<br>
Function until is first invoked by function lower:<br>
<br>
        lower  =  until (&lt;=x) decrease 0<br>
<br>
Here are the three arguments provided to function until:<br>
<br>
(1)  p is the partial function (&lt;=x), where x is the input to the floor function. Suppose x is this value: x  =  (-3.4)<br>
<br>
(2)  f is the function decrease<br>
<br>
(3)  y is 0<br>
<br>
Now you may argue, &quot;Hey, the third argument, y, is 0 and that&#39;s an Integer, so clearly the result of function until will be an Integer.&quot; However, that is not correct. The type of 0 is ambiguous, it could be an Integer or it could be a Double. This ambiguity can be seen by checking its type using WinGHCi:<br>


<br>
:type 0<br>
0 :: Num a =&gt; a<br>
<br>
The class Num is high up in Haskell&#39;s type hierarchy and it represents any number (Integer, Double, etc.). Thus, we cannot determine the type of function until&#39;s result just by examining its third argument. The other arguments will determine whether the 0 is an Integer or a Double.  Let&#39;s examine the first argument:<br>


<br>
        p is the partial function (&lt;=x), where x  =  (-3.4)<br>
<br>
p compares &quot;some value&quot; against (-3.4). Let&#39;s check the type of (-3.4) using WinGHCi:<br>
<br>
:type (-3.4)<br>
(-3.4) :: Fractional a =&gt; a<br>
<br>
The datatype Double falls within the class Fractional. So p compares &quot;some value&quot; against a Double.<br>
<br>
        Fundamental rule of Haskell: you cannot compare an<br>
        Integer against a Double, you can only compare a<br>
        Double against a Double.<br>
<br>
Recall that p compares &quot;some value&quot; against (-3.4). What is that &quot;some value&quot;? If we examine the body of function until we see that it is the third argument, y, and we know that y  =  0. Ah, now we know how Haskell will treat 0: since the 0 is being compared against a Double value Haskell will treat the 0 as a Double. Okay, now that we know the type of y we can plug it into the type signature for function until:<br>


<br>
until  ::  (a -&gt; Bool) -&gt; (a -&gt; a) -&gt; Double -&gt; a<br>
<br>
All a&#39;s must be of the same type, so the other a&#39;s must also be Double:<br>
<br>
until  ::  (Double -&gt; Bool) -&gt; (Double -&gt; Double) -&gt; Double -&gt; Double<br>
<br>
Therefore function until will return a Double value. For example:<br>
<br>
        until (&lt;=x) decrease 0          -- returns (0.0)<br>
<br>
The output of function until is assigned to function lower:<br>
<br>
        lower  =  until (&lt;=x) decrease<br>
<br>
So the result of function lower is a Double value.<br>
<br>
The output of lower is then input to upper and the Double datatype propagates through the entire chain of composed functions:<br>
<br>
        decrease . upper . lower<br>
<br>
The result of function floor is therefore a Double value.<br>
<br>
Okay, so how do we get floor to return an Integer value? The key is to prevent p in function until from casting the type of y to a Double. Recall function lower:<br>
<br>
lower  =  until (&lt;=x) decrease 0<br>
<br>
Notice that p is this partial function:<br>
<br>
        (&lt;=x)<br>
<br>
We must modify p to express, &quot;Hey, compare x against an Integer value that has been cast to a Double value.&quot; That is implemented using a Lambda (anonymous) function:<br>
<br>
        (\a -&gt; (realToFrac a) &lt;= x)<br>
<br>
Read that as: For whatever value, a, is provided convert it to a Fractional (Double) value and then compare it to x.<br>
<br>
Wow!<br>
<br>
So we are telling Haskell that the 0 is not to be treated as a Fractional (Double) value, it is to be treated as a Real (Integer) value.<br>
<br>
At last, we can implement function floor and it will return the desired Integer result:<br>
<br>
floor x = searchFrom 0<br>
                where   searchFrom      =       decrease . upper . lower<br>
                        lower           =       until (\a -&gt; (realToFrac a) &lt;= x) decrease<br>
                        upper           =       until (\a -&gt; (realToFrac a) &gt; x) increase<br>
                        decrease n      =       n - 1<br>
                        increase n      =       n + 1<br>
<br>
Notice that wherever function until is called (in lower and upper), the first argument, p, is a Lambda (anonymous) function that takes its argument, a, and casts it from a Real (Integer) value to a Fractional (Double) value. Here are a couple examples of using this revised floor function:<br>


<br>
        floor (-3.4)    -- returns (-4)<br>
        floor 3.4       -- returns 3<br>
<br>
Notice that floor now returns an Integer value, which is what we want.<br>
<br>
Here is the signature for floor:<br>
<br>
floor :: (Fractional a, Ord a, Real c) =&gt; a -&gt; c<br>
<br>
Read as: Invoke function floor with a Fractional (Double) value and it will return a Real (Integer) value.<br>
<br>
On page 83 Richard Bird shows a second version of function floor that uses a binary search:<br>
<br>
floor x = searchFrom (-1, 1)<br>
                where   searchFrom = fst . middle . cross(lower, upper)<br>
                        lower = until (&lt;= x) double<br>
                        upper = until (&gt; x) double<br>
                        middle = until done improve<br>
                        done (m, n) = (m + 1 == n)<br>
                        improve (m, n)  =  if p &lt;= x then (p, n) else (m, p)<br>
                                                 where p = (m + n) div 2<br>
<br>
That has multiple problems. First, it is syntactically not a well-formed Haskell program because the div operator (on the last line) must have back ticks ( ` ) surrounding it:<br>
<br>
                                where p = (m + n) `div` 2<br>
<br>
Second, the functions lower and upper invoke function until. The first argument to until must be a Lambda function as described above:<br>
<br>
                        lower = until (\m -&gt; (realToFrac m) &lt;= x) double<br>
                        upper = until (\n -&gt; (realToFrac n) &gt; x) double<br>
<br>
Third, the function improve compares p (an Integer) against x (a Double), so p must be cast to a Fractional (Double) value:<br>
<br>
                        improve (m, n)  =  if (realToFrac p) &lt;= x then (p, n) else (m, p)<br>
                                                   where p = (m + n) div 2<br>
<br>
With those three changes the function works as desired:<br>
<br>
floor x = searchFrom (-1, 1)<br>
                where   searchFrom = fst . middle . cross(lower, upper)<br>
                        lower = until (\m -&gt; (realToFrac m) &lt;= x) double<br>
                        upper = until (\n -&gt; (realToFrac n) &gt; x) double<br>
                        middle = until done improve<br>
                        done (m, n) = (m + 1 == n)<br>
                        improve (m, n)  =  if (realToFrac p) &lt;= x then (p, n) else (m, p)<br>
                                                   where p = (m + n) `div` 2<br>
<br>
Here are a couple examples of using the revised floor function:<br>
<br>
        floor (-3.4)    -- returns (-4)<br>
        floor 3.4       -- returns 3<br>
<br>
Notice that floor now returns an Integer value, which is what we want.<br>
<br>
Here is the signature for floor:<br>
<br>
floor :: (Fractional a, Ord a, Real c) =&gt; a -&gt; c<br>
<br>
Read as: Invoke function floor with a Fractional (Double) value and it will return a Real (Integer) value.<br>
<br>
/Roger<br>
<br>
_______________________________________________<br>
Beginners mailing list<br>
<a href="mailto:Beginners@haskell.org">Beginners@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/beginners" target="_blank">http://www.haskell.org/mailman/listinfo/beginners</a><br>
</blockquote></div><br></div></div></div></div>