What does `case divByA n (-d) of DividedByZero -> DividedByZero Result r -> Result (-r)` mean?

data DividedResult = Result Integer | DividedByZero
  deriving Show

divByA :: Integral a => a -> a -> DividedResult
divByA num denom = go num denom 0
    where go n d count
           | d == 0 = DividedByZero              -- A
           | d < 0 = case divByA n (-d) of       -- B
                DividedByZero -> DividedByZero
                Result r -> Result (-r)
           | n < 0 = case divByA (-n) d of       -- C
                DividedByZero -> DividedByZero
                Result r -> Result (-r)
           | n < d = Result count                 -- D
           | otherwise = go (n - d) d (count + 1) -- E

This is someone else’s solution to an exercise in a book. It took me some time but I think understand most of it. I don’t get the DividedByZero -> DividedByZero in guards B & C. As I understand it, B says,

  • "when d < 0
  • && divBy a is called with a positive numerator and negative denominator,
  • convert Result r to Result -r

Now that I’m looking at it again, that last point doesn’t seem clear to me.

I really dont get why B & C have DividedByZero -> DividedByZero. I would have guessed Integer -> Integer.

I think this is the part that has confused you. The case divByA n (-d) of part is basically calling the function again but now with a negated denominator (which makes it positive, because this only happens if the check d < 0 succeeds) and then inspecting the result. If the result is DividedByZero then the final result should be DividedByZero too. If the result is a “real” result then we should return the negated version of that, because we negated the denominator (and n/(-d) = -(n/d)).

So those two d < 0 and n < 0 checks are just to simplify the function so that in the rest of the cases you can assume that the numerator and the denominator are positive.

I see 2 or 3 things I was confused about
1st given my overall confusion I missed that the second guard was d < 0 and thought it was n < 0. That kind of thing should less as I get used to reading Haskell.

2nd I was looking at case divByA n (-d) of as a kind of pattern matching. Now I see that whatever is between case & of gets evaluated.

So the rest says if case divByA n (-d) of is type ofDividedByZero return DividedByZero or if it is type of Result return the negation of the result.

Hopefully I’m interpreting all that correctly now.


1 Like

And I guess I could look at case xx of as similar to a switch in other languages, such as JavaScript, except it is matching on types instead of values. That sound about right?

Not quite, because case ... of is matching on values. DividedByZero is one of the values of type DividedResult. Result n is also a value of type DividedResult for every n :: Integer.