3 ms·
Could it be the case that functional structure makes programs more reliable and easier to reason about in the large, but functional style/syntax may not be the
by jasperry 6y ago
Could it be the case that functional structure makes programs more reliable and easier to reason about in the large, but functional style/syntax may not be the best way to write code locally?
Trying to wrap an entire function's computation into one expression is a fun mental exercise, but the resulting code may be harder to read than a sequence of statements. Haskell's "do" notation seems to be an acknowledgment of this, but to me it's adding another layer of abstraction just to recover what imperative syntax gives in the first place. Why not start from the imperative model, and then find other ways to try to limit side effects and mutation? Languages like Rust may be heading in that direction; "Return of the statement" as it were.
- mrloba 6y agoI completely agree. Just write pure functions as much as possible and you're good. What goes inside a function doesn't matter so long as the function itself is pure, imo
- mrkeen 6y agoDo you have any examples of compilers or linters that assist with this? Any kind of error or warning would do.
- tome 6y agoHaskell has ST[1], which allows you to do mutable in place updates in a way that the compiler can guarantee are not visible from the outside. It's not particularly popular though. Typically it seems to be more convenient to either be thoroughly pure or accept mutability and use IO. [1] https://hackage.haskell.org/package/base-4.14.0.0/docs/Control-Monad-ST.html https://hackage.haskell.org/package/base-4.14.0.0/docs/Contr...
- jacinabox 6y agoThere's also the probably underappreciated packages ref-tf and ref-fd which let you write code that is polymorphic over the type of state reference. These can make 'ST' more acceptable because you don't have to make the decision of what state reference to use up front.
- mrloba 6y agoNot really unfortunately. In typescript/javascript you have a few options, but none that are any good. In js you can freeze an object to avoid mutation, but there's a performance penalty and a lot of hassle. As for side effects, you have the async keyword which often tells you if a function contains a side effect or not. In typescript you can use readonly for objects and arrays to avoid mutation, but it becomes a hassle for nested objects, and it doesn't work for local state where it's actually ok to mutate things. There is an issue open for typescript that proposes to add a "pure" keyword, but I think it's quite hard to implement. What I do instead these days is to separate pure from impure by using separate files, but as you noted in a sibling comment, this can quickly fall apart if people aren't onboard with the idea.
- mrkeen 6y ago> Why not start from the imperative model This video gives a bit of discussion around that point: https://www.youtube.com/watch?v=iSmkqocn0oQ https://www.youtube.com/watch?v=iSmkqocn0oQ My take on it is that it's too hard to put the side-effect genie back into the bottle once you take it out. It's hard to write side-effect-free code out of side-effectful pieces. E.g. You can't make a reasonable transaction system if you allow side-effects. You just have to hope that the programmer doesn't include any code that can't be rolled back. > Haskell's "do" notation seems to be an acknowledgment of this, but to me it's adding another layer of abstraction just to recover what imperative syntax gives in the first place. Haskell do-notation and Scala for-comprehensions kick arse and I always miss them when I don't have them. I think lack of do-notation is my biggest complaint about Java syntax.