2

I have following function based on McCarthy 91 principle:

mc91 :: Integer -> Integer
mc91 n
    | n > 100 = n - 10
    | otherwise = mc91 (mc91 (n + 11))

when I type in the prelude mc91 85 I've got 91.

I could not configure it out, how it is expanded and why do I've got 91.

duplode
  • 31,361
  • 7
  • 69
  • 130
softshipper
  • 26,415
  • 36
  • 123
  • 260

2 Answers2

6

Let's first analyze the function. There are two cases:

  • in the case n > 100, then we return n-10; and
  • in the case n <= 100, then we calculate n+11, and we do two additional steps.

There are thus two possible "steps": one where we decrement with 10, and one where we increment with 11. We can visualize this with a graph, like:

graphical representation of the McCarthy91 function

The edges of the first case are denoted in black, the edges of the latter case are denoted in red.

What we notice is that there is a loop here: 92 -> 103 -> 93 -> 104 -> 94 -> 105 -> 95 -> 106 -> 96 -> 107 -> 97 -> 108 -> 98 -> 109 -> 99 -> 110 -> 100 -> 111 -> 101 -> 91 -> ...

Let's assume for now that - regardless of the original value - we will always end up in that loop. Now the loop always interleaves a black edge, and a red edge, except for the 111 -> 101 -> 91 part, which consists out of two black edges.

Since a red edge introduces two additional recursive calls, that means that, if we take a red hop, we get the next black and red hop for free. The next red hop will again add two recursive calls to the "todo list". So as a result, if we start in the loop, and we first take a red hop, we will keep running through the loop. This holds as long as we do not take the 111 -> 101 -> 91 part of the loop. Since those are two black edges, we can get out of recursive calls to perform and thus stop at 91 (since we always get two additional hops per red hop).

As a result if we start at a certain node in the loop and we immediately take a red hop, regardless of the number of recursive calls we still need to do, we will eventually stop in 91: each time we do a complete loop, we "lose" one recursive call, so eventually we will run out of remaining recursive calls and stop in 91. So now we know that if we start, for instance at 94 with an arbitrary number of recursive calls, we will stop at 91.

Now we still need to show that - given the number is less than 100 - we will end up in the loop, and that the first node we encounter in the loop is a node from which a red edge begins. We know that all numbers in the range of 91..100 are in the loop. Any number that is smaller than 91, will result in a red hop and will be incremented with 11. Therefore - as is partly shown in the graph - all numbers less than 91 will end up in the range of [91..100] eventually by always using red edges.

Based on the above reasoning, a more efficient version of the function would be:

mc91' n | n > 100 = n-10
        | otherwise = 91

Now for your given sample input (85), we see that the program will evaluate to:

   mc91 85
-> mc91 (mc91 96) -- we are in the loop now
-> mc91 (mc91 (mc91 107))
-> mc91 (mc91 97)
-> mc91 (mc91 (mc91 108))
-> mc91 (mc91 98)
-> mc91 (mc91 (mc91 109))
-> mc91 (mc91 99)
-> mc91 (mc91 (mc91 110))
-> mc91 (mc91 100)
-> mc91 (mc91 (mc91 111))
-> mc91 (mc91 101)
-> mc91 91 -- we reached 91, and thus removed one recursive call
-> mc91 (mc91 102)
-> mc91 92
-> mc91 (mc91 103)
-> mc91 93
-> mc91 (mc91 104)
-> mc91 94
-> mc91 (mc91 105)
-> mc91 95
-> mc91 (mc91 106)
-> mc91 96
-> mc91 (mc91 107)
-> mc91 97
-> mc91 (mc91 108)
-> mc91 98
-> mc91 (mc91 109)
-> mc91 99
-> mc91 (mc91 110)
-> mc91 100
-> mc91 (mc91 111)
-> mc91 101
-> 91 -- we hit 91 a second time, and now the last recursive call is gone
Willem Van Onsem
  • 321,217
  • 26
  • 295
  • 405
4

Lets expand your code:

mc91 85
mc91 (mc91 96)
mc91 (mc91 (mc91 107))
mc91 (mc91 97)
mc91 (mc91 (mc91 108))
mc91 (mc91 98)
mc91 (mc91 (mc91 109))
mc91 (mc91 99)
mc91 (mc91 (mc91 110))
mc91 (mc91 100)
mc91 (mc91 (mc91 111))
mc91 (mc91 101)
mc91 91... --It is a pattern here
...
mc91 101
91

If you see the recrusive calls, you will realize that it will reduce it once it achieves 100 or higher, ending in a (mc91 101) call that will bring us the last 91 result.

Netwave
  • 23,907
  • 4
  • 31
  • 58
  • In the 107 line there are too many `mc91` I think. There should be only three of them, right?. This is propagated to the subsequent lines. – chi Jun 08 '17 at 10:37