5 ms·
> Honestly, I still don’t really understand imperative languages. Why would you want things to mutate? Because in the computer, things need to mutate, and so a
by theseoafs 12y ago
> Honestly, I still don’t really understand imperative languages. Why would you want things to mutate?
Because in the computer, things need to mutate, and so a language that doesn't mutate is therefore far from the computer.
EDIT: Put another way: Haskell does support mutation, but inside of particular monads. So obviously mutation is useful. Learn why it's useful in Haskell and you'll see why it's useful elsewhere.
- DonPellegrino 12y agoIn my opinion you're seeing it wrong. The beauty of FP is that from your code's point of view there is no mutation. Everything is immutable, everything is clean and beautiful. But then the compiler is able to tell that your variable that's used as an argument to a tail-recursive function is actually being redefined on every recursive call and treats it as a mutable variable in the output assembly. Similar ideas are applied throughout those languages. For example, in OCaml you have the notion of "functional record updates". Basically you update structs by getting a whole copy back with the modified fields changed accordingly. Under the hood though, what you get is just the changes and the other fields point to the original struct. Basically there is a difference between what your code says and what the compiler outputs, but in the end the result is the same, the compiler is just smart enough to rewrite it for you. You're right that it's further from the computer, but only for what you type in your editor. I highly recommend the book Functional Data Structures (it's on Amazon) if these sort of brilliant compiler optimizations interest you.
- theseoafs 12y ago> The beauty of FP is that from your code's point of view there is no mutation. The beauty of pure FP is that from your code's point of view there is no mutation. The only functional language you mentioned in your post is OCaml, which is impure and supports ad-hoc mutation, like every other language in the ML family, and like every other functional language except for a select few like Haskell and Miranda and their derivatives. Moreover Haskell supports other kinds of mutation besides fusion and tail-call elimination; it just does it behind a pure interface. See, for example, http://hackage.haskell.org/package/array-0.1.0.0/docs/Data-Array-IO.html http://hackage.haskell.org/package/array-0.1.0.0/docs/Data-A... . So we're back at the same place: obviously mutation is useful since even Haskell goes out of its way to make sure you have access to it.
- AnimalMuppet 12y agoI think the pure interface is the useful part. If there's mutation, but I can firewall it behind a (non-leaky) pure interface, then I don't have to reason about that mutation if I'm looking at code outside the interface. That's a huge win. Now, OO tries to do the same kind of thing - hiding things behind an abstraction that you don't have to think about from outside the abstraction. The problem is, all the abstractions leak. Does Haskell's hiding mutation behind a purely functional interface leak? I don't know enough to say, but I think it's a critical question.
- BillMryes 12y agoIn the computer, you also have no descriptive variable names and make excessive use of gotos. This is far from a good argument. > Haskell does support mutation, but inside of particular monads. You are mistaken. Monads do not involve mutation; that would defeat their entire purpose. Although it's true that the monadic code is being compiled into assembly that involves mutation, just as $LANGUAGE code is being compiled into assembly that includes a lot of goto.
- tome 12y ago> You are mistaken. Monads do not involve mutation. Indeed. IO and ST involve mutation. They just so happen to be instances of Monad, but that's tangential.
- rtpg 12y agothey don't involve mutation on the language semantics level. The mutation happens through the runtime (via calls to the C FFI). In reality they're implemented in a mutation-heavy way for performaance reasons, but on the language level absolutely no mutation happens ( it's the whole World -> (Result, World) analogy)
- carterschonwald 12y agoThey're not done via cffi . its all compiler supported primops that get optimized and lowered to target native assembly.
- theseoafs 12y agoThe whole point about where the mutation happens and how the language remains pure in spite of it is not awfully relevant. The point is that Haskell does support real, bona-fide mutation in its standard library (see for example its support for stateful IO arrays). So obviously mutation is useful, regardless of whether you're doing that mutation behind a pure interface.
- BillMryes 12y agoTo add to what rtpg says, if you look at an actual, monadic example of an IO: putStrLn "What is your name?" >> getLine >>= \name -> putStrLn ("Hi, " ++ name ++ "!") It's just a giant chain of instructions, each previous result feeding into the next. Nowhere do we assign anything, modify anything, etc. No mutation.
- tome 12y ago> in the computer, things need to mutate, and so a language that doesn't mutate is therefore far from the computer I hear this argument a lot but I don't buy it. You could also say "In the computer, things are highly asynchronous quantum-level electrical fluctuations, and so a language that doesn't model highly asynchronous quantum-level electrical fluctuations is therefore far from the computer." which is clearly invalid. Some explanation is needed of why the argument for mutation holds, but for quantum fluctuations does not hold.
- TheDong 12y agoThe difference is abstraction. When you code, you're building on top of assembly / cpu registers and instructions. The fact that X86/64 runs on a bunch of electrical fluctuations is actually inconsequential and an implementation detail. Any x86/64 processor built of transistors naturally needs to take into account the behavior of the transistors it's made up of. But once you've gone above the micro-code/processor level, those details are fully abstracted. Regardless what programming language you use, that is abstracted away identically and matters not. However, the fact that registers in the process and memory locations exist and mutate is not something abstracted away from every language. It's abstracted in some, but not others, so it's valid to say that this difference is within the scope of the programming language. That is why the argument differs. If the above isn't clear, I'd be happy to give another go at explaining it.
- Peaker 12y agoSo it's just a matter of abstracting less or more of the implementation details. In Haskell, the mutation necessary to implement pure, lazy computation is an implementation detail, just like manual memory management or quantum fluctuations.
- Rusky 12y agoOne of those implementation details is hidden away underneath the hardware interface and not visible to software. There are plenty of better examples to make this point with- named variables and functions, control structures, etc. And these make it clear that the argument is really about the importance of this particular abstraction: where and when memory is used for which values.