Live data from Hacker News

Functional languages should be so much better at mutation than they are

cohost.org

151–160 of 188 posts

Re: Functional languages should be so much better at mutation than they are

#151
post #99

Earlier quoted context omitted.

Can you elaborate?

They don't get stack traces, for one. (That's arguably the biggest problem with Rust: .unwrap() gives you a stack trace, but has problems; whereas ? erases your stack trace.) In principle, static analysis could identify unhandled exceptions, then trace the exception, then make that information available to the top-level "Err returned from main" handler. In practice, that's never going to happen in Rust.

Sum types can have stack traces by adding a stack trace on creation. `Result` does not have a stack trace, but `Result` sure does. YMMV as to whether it makes sense to do that in any particular circumstance.

Re: Functional languages should be so much better at mutation than they are

#152
post #147
post #140

Earlier quoted context omitted.

This is a hill I will die on. Probably literally. If you are writing in a metaphor of equations, than yes, mutation is almost certainly going to bite you. If you are writing in a metaphor of process, you almost certainly want to manage, as you say. I feel that early texts were good at this. Turtle Geometry is my personal favorite book in this vein. I seem to recall we spent a long time going over how to double buffer…

> The entire point is to change things We've other 'entire points' along the way. Allocation and freeing of memory are fundamental to computing. We don't do malloc and free any more. Control-flow (selecting which instruction to follow next) is also fundamental. We don't to goto anymore.

I'm not entirely clear what you mean. I can easily see malloc/free in the realm of "incidental complexity." Many of the abstractions in process descriptions are absolutely not incidental, though?

Control-flow is an awkward choice there, as goto is not necessarily fundamental for how control-flow is run for a lot of code. And I have absolutely used labeled break/continue in Java before for a control loop that ran great until people tried to refactor to use more indirect control.

I also think it is interesting as I greatly prefer code where you can do basic left/right and top/down reading to know what is intended by the code.

At any rate, my original intent was to discuss code that is controlling something works really well if you embrace a metaphor for the code you are in.

Re: Functional languages should be so much better at mutation than they are

#153
post #56

Earlier quoted context omitted.

Aside: Could a Rust library provide an Rc interface but use a more sophisticated GC algorithm underneath?

You can, but it turns out that, as one may intuitively expect, a GC is never needed unless implementing a VM for a GC-based language or an API that required GC like fd passing on unix domain sockets, and those generally want an ad-hoc GC instead tailored to whatever you are implementing. Since it's not needed and it's massively worse than reference counting (assuming you only change reference counts when essential an…

Many use GC languages for productivity in code where that’s more important. Far as slowdowns, there are concurrent and real-time (fixed timing) GC’s out there which reduce or avoid the problems you mention. JX OS also let you mix different GC’s for different components.

So, there’s a performance hit of some kind with optional tuning that takes no expertise. Many people would go for those tradeoffs for some applications. Especially if they got to keep using safe, no-GC code in their libraries with their efficiency benefits.

Re: Functional languages should be so much better at mutation than they are

#154
post #65

> ...functional programming is mostly about avoiding mutation at all costs Slightly different perspective from Grokking Simplicity[1]: functional programming is not about avoiding mutation because "mutation is bad." In fact, mutation is usually the desired result, but care must be taken because mutation depends on when and how many times it's called. So good FP isn't about avoiding impure functions; instead it's abou…

[deleted]

Re: Functional languages should be so much better at mutation than they are

#156
post #128

> A lot of people think that functional programming is mostly about avoiding mutation at all costs. People should try to stop thinking of mutation as something to be avoided, and start thinking of it as something to be managed. Mutating state is good. That's usually the whole point. What's bad is when you create "accidental state" that goes unmanaged or that requires an infeasible effort to maintain. What you want is…

> The second part is where functional programming shines -- you have a simple way to just recompute all the derived things. And since it's presumably the same way the derived things were computed in the first place, you don't have to worry about its logic getting out-of-sync.

Thinking this further, this is also performance related. I think there is an interesting relationship between FP and DOD:

A technique of data oriented design is to keep state minimal and lazily derive data when you actually need it, which may involve recomputing things. The rationale is that compressed, normalized data requires less fetching from memory and computation on it is faster.

In contrast caching and buffering, both of which are heavily stateful and require a lot of additional memory, are often necessary, because they minimize inherently slow operations that are out of your control. Those kinds of things are often best implemented as (computational) objects with encapsulated, internal state and small, general interfaces, like OO has taught us.

But once the data in your control, this mindset has to be flipped on its head. You want to model your in-memory data not that differently from how you'd model for databases: Neatly aligned, normalized data, with computed columns, views and queries to get richer answers.

Interestingly if you follow this approach, then code starts to look more similar to functional code, because you potentially need the whole context to derive values from it and a lot less like independent objects that send messages to each other.

Re: Functional languages should be so much better at mutation than they are

#157
post #29

I recently ran into this issue when trying to memoize a simple numerical sequence in Hoon (yes, that Hoon. I know, I know...). Let's use the fibonacci sequence as an example. Let's write it the classic, elegant way: f(n) = f(n-1) + f(n-2). Gorgeous. It's the sum of the two previous. With the caveat that f(n=0|1) = n. In Python: # fib for basic b's def fib(n): ## Base case if n == 0 or n == 1: return n return fib(n-1)…

Urbit fixes this

Re: Functional languages should be so much better at mutation than they are

#158
post #35

Earlier quoted context omitted.

Yes, but transformers have a few drawbacks: the order of stacking alters behaviour, and you need to write n^2 instances for n transformers. Compare ExceptT e (StateT m a) and StateT (ExceptT e m a): if you just want your computation to have state and exceptions the difference shouldn’t matter.

> if you just want your computation to have state and exceptions the difference shouldn’t matter But... you don't just want that. You almost certainly care whether state changes are discarded when an exception is thrown. I don't claim that the types there are the most obvious or natural way to specify that, but there is a meaningful difference that shouldn't be handwaved away.

The fact that with transformer stacks you can wind up with state changes being discarded on exception if you get the stack arranged in a particular order isn't what I'd call a _feature_ of transformer stacks :-)

If effect A is invoked before effect B, effect A should happen and stay that way: if I update state before an exception is thrown, the update should persist. If I send a network message before an exception is thrown, the network message is still sent. If I launch the nukes before an exception is thrown, the missiles are still flying.

If I want to batch up state updates to only happen together as a unit, I'll use a transaction effect.

Re: Functional languages should be so much better at mutation than they are

#159
post #144
post #128

> A lot of people think that functional programming is mostly about avoiding mutation at all costs. People should try to stop thinking of mutation as something to be avoided, and start thinking of it as something to be managed. Mutating state is good. That's usually the whole point. What's bad is when you create "accidental state" that goes unmanaged or that requires an infeasible effort to maintain. What you want is…

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…

> Or other choices. I like mutable islands in a generally immutable/unshared global space as a design point myself, [...]

That's pretty easy to do in eg Haskell or even Rust.

Re: Functional languages should be so much better at mutation than they are

#160
post #65

> ...functional programming is mostly about avoiding mutation at all costs Slightly different perspective from Grokking Simplicity[1]: functional programming is not about avoiding mutation because "mutation is bad." In fact, mutation is usually the desired result, but care must be taken because mutation depends on when and how many times it's called. So good FP isn't about avoiding impure functions; instead it's abou…

You don't need impure functions. You can manage mutation with pure functions just fine. See how Haskell or Clean do that.

(Of course, if you really need impure functions for eg performance, `unsafePerformIO` has you covered in Haskell.)

Post reply on HN