Earlier quoted context omitted.
I like to say that immutability is a really good idea in the 1990s, especially considering how counterculture it would have been at the time. I don't mean that as diminutive or patronizing, I'm serious. It was a good cutting edge idea. However, nobody had any experience with it. Now we do. And I think what that experience generally says is that it's a bit overkill. We can do better. Like Rust. Or possibly linear type…
>And I think what that experience generally says is that it's a bit overkill. We can do better. Like Rust. Or OCaml perhaps ? They have taken a very pragmatic approach to fp and allow mutations because thats the pragmatic choice sometimes.
Functional languages should be so much better at mutation than they are
181–188 of 188 posts
Re: Functional languages should be so much better at mutation than they are
#182Earlier quoted context omitted.
>And I think what that experience generally says is that it's a bit overkill. We can do better. Like Rust. Or OCaml perhaps ? They have taken a very pragmatic approach to fp and allow mutations because thats the pragmatic choice sometimes.
The funniest thing is that to compile Rust, enabling various compiler features (like borrow checker etc), the code has to be transmuted into non-mutable one Single Static Assignment form :V
Re: Functional languages should be so much better at mutation than they are
#183The lazy clone in HVM may be a viable approach to mutation
EDIT: Found this: https://github.com/HigherOrderCO/HVM1/blob/master/guide/HOW....
Re: Functional languages should be so much better at mutation than they are
#184Earlier quoted context omitted.
The funniest thing is that to compile Rust, enabling various compiler features (like borrow checker etc), the code has to be transmuted into non-mutable one Single Static Assignment form :V
And in the functional world, Lean 4 achieves language level support for local mutation, early return, etc. in the same way, by converting it into non-mutating code: https://dl.acm.org/doi/10.1145/3547640
Sure, ultimately the code mutates values in place, but the specific actions are modeled as pure operations
Re: Functional languages should be so much better at mutation than they are
#185There is a way to do FBIP without reference counting - use immutable store semantics (always copy). At that point you are doing a lot of copying but Haskell etc. are actually pretty good at managing this sort of profligate duplication. And of course it is possible to use RC-at-compile-time and other analyses to optimize away the copying - the difference is that runtime RC is not required like it is in Koka. There is…
> use immutable store semantics (always copy). What does "always copy" mean? What and why would you copy?
Re: Functional languages should be so much better at mutation than they are
#186IMO, Functional Programming was a zero interest rate phenomenon. Some mathematicians suffering from professional deformation believed that programming should adhere to the purity of mathematical conventions... Meanwhile, there was no proof whatsoever to support the hypothesis that constraining programming to such conventions would be beneficial in a practical sense. FP proponents spotted a small number of problems wh…
Interesting: I came to a similar conclusion when I developed a state management system I coined "nation state." (A group of related variables with scope that is between local and global scope.) Svelte has these stores that are globally reactive. The reactivity is convenient, but the stores can also be globally updated. This could result in chaos that I wished to corral. So I tweaked stores so they remained globally r…
It's interesting how FP community took one issue which affects many OOP implementations and decided to throw the baby out with the bathwater... Completely ignoring the reason why OOP was invented in the first place.
I've worked on several FP projects. First of all, they're never pure FP projects because that's just not possible. Those which were close to pure FP were a tangled mess of curried functions. Many modules had weird technical names with unclear responsibilities, most features had to traverse many different files/functions with lots of unrelated data passing through various modules with detailed child state which had to be passed down from high up in the 'module' hierarchy and traverse many layers to finally get to the module which would actually use that state. Higher level modules exposed complex functions with complex input and output parameters (had to concern themselves with the highly specific state requirements of child and parent modules; including configurations!) which would have to be modified for every single high level AND low-level requirement change... I'm not surprised why big companies who use FP started using monorepos; FP makes monorepos necessary because every small change requires updating a large part of the code hierarchy because everything is intertwined with everything else (tight coupling). The higher level components have to know exactly what state the child components expect because the data comes from a central place and must be passed down.
The alternative approach would be to have each child sync itself with a global store; but then, it implies that you no longer have a single owner for each piece of state; thus, you might end up with different children which have overlapping responsibilities which update the same part of the global state, creating 'spooky action at a distance' which makes it hard to trace where the change originated... This takes us back to the very reason why FP community invented FP in the first place. In other words, FP doesn't solve the 'spooky action at a distance' problem which was its entire raison d'etre.
Frameworks like React had to invent a whole host of technical concepts and tools to help manage and track complex state changes... E.g. Redux, Saga, etc... But then we still end up with a situation where all our components are tightly intertwined with the specific implementation of that specific framework since the number of variations of how people use Redux/Sagas, etc... across different projects/companies is substantial. This means that components built for one project are generally not immediately compatible with components built for a different project. If the two projects use a different global store mechanism or they use the same mechanism but have different names for the same actions (to dispatch state changes), the components will not be compatible across different projects without a lot of refactoring to bring the component into alignment with both projects. This isn't modular! This isn't easy to read! It's not maintainable!
Re: Functional languages should be so much better at mutation than they are
#187Earlier quoted context omitted.
> The point is that contrary to what the article states ML developers are not avoiding mutations because they are uneasy to use but because they trust their compiler when they know it will do good. Proof is that in other case they will use mutations when it makes sense to do so because the compiler does not do a good job. It will do a good job, yes. Will it do the best possible job compared to some other algorithm or…
Oops, this had a performance bug. Instead of: if d.length = Array.length d.values then begin d.values the array reallocation should actually be: if d.length = Array.length d.values then begin let new_array = Array.make (Array.length d.values * 2) x in Array.blit d.values 0 new_array 0 (Array.length d.values); d.values otherwise we allocate about a third more memory than needed. It's telling that even with this perfor…
It can't be otherwise if you're just assuming a straightforward compilation model where your written roughly reflects the assembly code that's generated. This just isn't the case with better compilers though.
For instance, Haskell can often perform rewrites or fusion passes that entirely eliminates the loop and all intermediate data structures, effectively giving a near-infinite speedup compared to alternatives. You typically can't perform such optimizations when side-effects are in the middle of the computation, for numerous reasons.
Re: Functional languages should be so much better at mutation than they are
#188Earlier quoted context omitted.
Oops, this had a performance bug. Instead of: if d.length = Array.length d.values then begin d.values the array reallocation should actually be: if d.length = Array.length d.values then begin let new_array = Array.make (Array.length d.values * 2) x in Array.blit d.values 0 new_array 0 (Array.length d.values); d.values otherwise we allocate about a third more memory than needed. It's telling that even with this perfor…
> Honestly, how could it be otherwise? It can't be otherwise if you're just assuming a straightforward compilation model where your written roughly reflects the assembly code that's generated. This just isn't the case with better compilers though. For instance, Haskell can often perform rewrites or fusion passes that entirely eliminates the loop and all intermediate data structures, effectively giving a near-infinite…
(You are right on the general hand-waving level that such optimizations are sometimes possible. But there are no fuseable intermediate data structures in this particular problem.)