4 ms·
Explicit recursion is really a foundational primitive upon which other abstractions should be built, including looping constructs. It is similar to goto, in tha
by willtim 8y ago
Explicit recursion is really a foundational primitive upon which other abstractions should be built, including looping constructs. It is similar to goto, in that it is a form of unstructured programming. Functional programmers prefer using maps and folds.
Loops are not necessarily close to what a CPU actually does either, especially one supporting vector operations or out-of-order execution. Loops imply an ordering which may or may not be actually exist and many compilers are complicated by their presence.
Debuggers are a problem for any suitably high-level abstract code. Would a step-by-step word-at-a-time debugger help to debug a SQL query or even a complex arithmetical expression from Fortran? There is no getting away from the fact that high-level domain-specific code needs high-level domain-specific debuggers to be built alongside.
- lucio 8y agoIn current hardware, recursion is far from a "primitive". jump is a primitive. Looping is above that, and recursion is way above iteration in a "foundational vs. composed" hierarchy. https://stackoverflow.com/questions/2651112/is-recursion-ever-faster-than-looping/28033212#28033212 https://stackoverflow.com/questions/2651112/is-recursion-eve...
- willtim 8y agoI was advocating recursion as a foundational primitive for a compiled high-level or intermediate language, not as part of some hardware instruction set. Current hardware is a bit of a legacy mess, we should resist the temptation to take on its baggage.
- Const-me 8y ago> functional programmers prefer using maps and folds. I know and I don’t think these are always good things. > Loops are not necessarily close to what a CPU actually does either Indeed, not necessarily, but very often. Unless automatic vectorization is involved, long loops are very often quite close to the machine code uploaded to CPU. Inside the CPU it’s free to do whatever, but on the public API, it’s still loop instructions. > the fact that high-level domain-specific code needs high-level domain-specific debuggers to be built alongside. That’s not a fact, that’s your opinion. I don’t code SQL nor Fortran, mostly C++ and C#, sometimes Python and others. The debuggers I have in corresponding IDEs are already built, they are sufficiently high-level for domain specific code, but the debuggers themselves aren’t domain specific, they are pretty general purpose.
- willtim 8y ago> I know and I don’t think these are always good things. Maps and folds do make structure explicit though. For example, it is very easy for a compiler to vectorise a "map" operation. Folds will always terminate. > The debuggers I have in corresponding IDEs are already built, they are sufficiently high-level for domain specific code. But does your debugger allow you to visualise the intermediate steps of an arithmetic expression? Does it understand Iterables/Enumerables and allow you to capture and inspect them? Can it handle concurrency and parallelism, or help you make sense of callbacks for non-blocking IO etc? My point is that the debugger is simply not as general purpose as most claim it to be. It sees the world word-at-a-time and only allows you to step statement-by-statement. It does not understand the composite data structures or control structures that you have built. This is less of a problem with low-level code, as typically there is limited abstraction. But it will be a problem for any sufficiently high-level abstract code (functional or otherwise).
- Const-me 8y ago> it is very easy for a compiler to vectorise a "map" operation For a general map function, it’s insanely hard problem. It’s only trivial if the map function is trivially simple e.g. `return x*2`. > does your debugger allow you to visualise the intermediate steps of an arithmetic expression? No, and I write my code in a way so the expressions aren’t too complex. When they grow to be that complex, I break them into multiple steps, keeping intermediate results in separate variables. BTW my primary motivation is readability, debugging is secondary. > Does it understand Iterables/Enumerables and allow you to capture and inspect them? I think so. > Can it handle concurrency and parallelism, or help you make sense of callbacks for non-blocking IO etc? Sure, debugging async-await code in .NET is almost as simple as old school non-scalable blocking IO code. > But it will be a problem for any sufficiently high-level abstract code Not a huge problem in practice. There’re simple ways to implement support for your custom composite data structures, e.g. natvis files in VC++. Also, in .NET you can run any code in debugger’s immediate window, while execution is paused. These simple methods aren’t effective in 100% cases, but often they are sufficient to debug, therefore saving a lot of time because no domain-specific debuggers are required.