Understanding why the Halting problem can't be solved

Reese did a very good job of explaining how a proof of the undecidability of the halting problem may be written in a way that explicitly makes use of diagonalization. I'll offer an informal gloss.

Diagonalization is employed to reach a contradiction that forces us to abandon an assumption. Here the assumption is the existence of a TM (let's call it $H$) that decides the halting problem.

Diagonalization is applied by building a table $A$ such that that $A_{i,j}$ says whether the $i$-th TM halts on input $j$. We then say, "Let's build a TM that on input $i$ does the opposite of TM $i$."

Now the question is, "Does such a Turing machine exist?" It's not hard to see that given $H$, one can build the desired TM; but then this TM is not in the table, because it was built by diagonalization and yet the table lists all TMs (TMs can be enumerated) ... Contradiction!

The only assumption we can give up is the existence of the TM $H$ that decides the halting problem, which is what we do, so that we are not forced to admit that there is a TM that disagrees with TM $i$ on input $i$ for all $i$.

How would we build the "diagonal TM" given $H$? Just as explained in the "other" proof: duplicate the input, let $H$ decide whether the input TM halts when it reads itself, and then do the opposite of what $H$ said. This last step is diagonalization.


It doesn't have to do with the uncountability of the real numbers, though the argument is similar.

Based on your most recent edit in response to the comments, it sounds like you don't want the traditional proof, you want the proof your professor was providing. What your professor was doing is in no way standard, so we can only guess; but here's what I think the argument was.

The Turing machines aren't just countable, they can be listed by a Turing machine. So we have an algorithm that lets us list the Turing machines, in order. Suppose we had an algorithm, $H$, that would tell us whether a given Turing machine would halt on a given input. We now construct a new algorithm, $T$, as follows: to determine $T(n)$, we look at the $n$th Turing machine, and ask $H$ whether it halts on input $n$. If it doesn't, we say $T(n) = 0$. If it does, we run that $n$th Turing machine on input $n$, and eventually get a result; let $T(n)$ be that result plus one.

Now, $T$ is an algorithm, so it's represented by a Turing machine. But all the Turing machines were on our list, so $T$ is on our list. Say it's the $N$th Turing machine on our list. What's $T(N)$? If $T$ doesn't halt on input $N$, then at the $N$th step of our construction we decided that $T(N) = 0$, so $T$ does halt on input $N$, a contradiction. If $T(N) = k$ for some $k$, then we decided that $T(N) = k + 1$, another contradiction. But those were the only options - either $T(N)$ doesn't halt, or it eventually outputs some $k$. So this contradicts the supposition that $T$ is actually a Turing machine, which means that the key element - the halting algorithm $H$ - must not exist.


Personally, when I learned the halting problem, I like to think of the machine leading to contradiction as the following concrete C program:

#include <stdio.h>
#include <stdbool.h>

/* If we assume the existence of a halting machine 'does_it_halt'.  */
bool
does_it_halt(void *turing_machine, void *input);

/* Then we can build the following machine 'absurd'.  */
void
absurd(void *input)
{
  if (does_it_halt(input, input))
    {
      while (true) {/* infinite loop  */}
    }
  else
    {
      return;
    }
}

/* Now if we run the machine 'absurd' with itself as input, does it halt?  */
int
main(void)
{
  absurd(absurd);
  return 0;
}