That's when I understood where TDD came from: dynamically typed languages require so many tests to work reliably that we better write those tests first so we're not tempted to omit them.
Anyway, I redid the whole thing in OCaml, and this time got lots of compile time errors. Which I could correct, and once the compiler was happy, well… my program was basically correct.
---
I still don't rule out that other people's brains are wired fundamentally differently. I don't expect it, it would surprise me, but I honestly don't know. What I do know is that dynamic typing is not for me. I'll suffer through it to get other advantages (Python's comprehensive library for instance), but that's about it. Dynamic typing and I are otherwise done.
The key to writing type-less code is making it so simple that you could cry. Avoid being clever at all costs. However, it's almost the exact opposite when you have a nice compiler checking everything, you can be mighty clever and know that it will work.
I'm lucky in that we can solve a problem in a myriad of languages, depending on if it needs to be "realtime", or can be precomputed. There are some types of problems I'd rather solve in Scala, and others, Python or PHP. It just depends.
I can't help but interpret this as "the key to writing type-less code is choosing problems so simple that you could cry". In other words, dynamic typing doesn't scale.
When I have a very simple problem to solve, sure, I won't mind dynamic typing. For anything worth more than an hour of coding however, I'll definitely reach for more reliable tools.
/Too many arguments at work are over dogma and I have to spend a lot of my time reminding people that there are options. That's all. There are options. Your kneejerk response to a problem might be fine -- might be right -- but there are always options.