This presentation is very good! A few days ago, I started thinking how code from a functional language could be converted to imperative code for better performance, with in-place operations (instead of object regeneration) and a complex (and likely slow) optimizing compiler. However, things like closures, composition at runtime and partial function application just made everything 10x harder.
> However, things like closures, composition at runtime and partial function application just made everything 10x harder.
Closures are just functions with an extra parameter for the environment (free variables). Subsequent passes after desugaring can treat them like any other function.
Function composition and currying should also be static transformations. Maybe you made it harder than it has to be?
If functions are higher order then the distinction between plain functions and closures is retained (unless you treat all functions as closures). This is because the data needs to be passed around in the function pointer. If not higher order then yes, they desugar
Implementing these things is maybe easy for you ;) but for myself, doing it well, I would definitely not describe as a walk in the park
It is true you need to pass the environment around, but if the language you are implementing also has objects or structs then you will need to implement that anyway.
My main objection to the grand parent is the idea that functional languages are 10x more difficult to implement than mainstream languages. Maybe that is true for Haskell, but most functional features can be compiled efficiently without much additional complexity. The complexity added by closures for instance would be closer to 1% than 10x.
That's the same curiosity that led me here: how much of higher-order functional programming could be implemented as zero-overhead abstractions over a C-like language, and what restrictions on language semantics would be the tradeoff?
I wonder what is a zero overhead abstraction. For instance closures are expensive (they malloc), but to what extent can we consider closures to be malloc'd structs; then potentially do away with the concept of structs -- because they've become a subset of the functionality provided by closures. At that point can we not consider closures as zero cost; because malloc of structs is essential to c, and with optimization we need be no more expensive
And to what extent does that hold true for every other feature? In some sense it is maybe always true
"First order IR" in the sense of "without lambda abstractions"? Then I guess this [0] would be a decent starting point for understanding it? It seems to describe mlton's compiler pass for flattening the higher-order functional parts with some kind of flow analysis. (?)
First order probably means no passing functions as values. That's somewhat imprecise, passing a function pointer to a function called call or apply seems fine. No passing closures around though.
One way to go is compilation to combinators, which are functions that don't have a runtime representation of a lexical environment, aka functions that can be serialised as C without change in semantics. Basically add arguments to represent closed over data and rewrite call sites.
On reflection I think continuation capture is a candidate for inherent overhead that cannot be eliminated - at least I can't currently see how to eliminate it - but then C can't do that. There's also the question of runtime cost of error detection, out of bounds etc, which C also doesn't do.
You probably need whole program compilation to desugar everything. And I'm essentially claiming a sufficiently smart compiler can make functional languages as fast as imperative, which has dubious empirical support. Stuff like hash tables are hard to express without mutation or overhead. Still, mlton and stalin (r4rs scheme) take a reasonable stab at it.
Probably fair to say that with today's compiler tech I'm wrong, but not in a fundamentally unsolvable tomorrow sort of way.
State monad as a first class language construct might help? You could allow actual mutations inside that and therefore if a lot of computation needs doing it could be more efficient.
Through virtualization (Termux + QEMU), it should be possible. However, unless you're running Windows for ARM (no need for x86-64 emulation), you may get the performance of a Pentium III. Natively, though, those OSes simply don't have drivers and bootloader for your tablet. If you were a systems programmer, you could write those yourself and, after months of work, you'd have something like https://www.worproject.com/
Maturity to fix most compiler bugs? Yes, on x86_64 (some bugs remain on other architectures). But you can still expect your code to break between zig versions.
Yes, and in this case 6W TDP and cheap enough for a $500 tablet seem like key drivers of the N200's design. Of course the Apple M1 is probably twice as fast at similar cost and power but compared to everything outside Apple the N200 looks pretty decent.
I don't know much about peak power consumption of these chips, but they are crazy efficient when idling / having little load. Plus, ARM support still sucks :-(
Though iOS is, out of the box, more private than stock (non-AOSP) Android, nothing compares to a custom ROM. You can even debloat android and disable play services, if you don't want to risk bricking your device, or if there aren't any custom ROMs available.
Of course, the average Joe wouldn't do that, but I guess most people on HN are quite tech savvy.
I for one have built enough Linux kernels from scratch, and patched enough Linux drivers into working — thanks, so no one can call me an average Joe when it comes to tech. However, I mostly left all of that behind outside of work years ago, I’m desperate for time, not money, and I have way better things to do with my time than dick around with a custom android build, thanks. You do you, but Apple provides me with a ‘good enough’ service that saves me a lot of time.