5 ms·
Pure functional programming is really about tracking and controlling effects by making them first-class, not avoiding them altogether. This has numerous benefit
by grumpyprole 4y ago
Pure functional programming is really about tracking and controlling effects by making them first-class, not avoiding them altogether. This has numerous benefits for reasoning, correctness and optimisation. Haskell allows mutable local variables, 'ST' references which can be used to build functions that are observably pure on the outside. The Haskell type checker will guarantee that no mutable state escapes. This is true "state encapsulation". It is completely acceptable for pure FP programming.
- galaxyLogic 4y agoSo mutable state is not bad, as long as it is "encapsulated"? I thought (from what I've read so far) that "no mutable state" is the definition of "pure FP". So should the definition of pure FP be "No un-encapsulated mutable state"? Instead state must always be "encapsulated". Where can I read more on this? Thanks
- jeffreygoesto 4y agoSomewhere down towards the transistors, the change has to happen. The registers of the machine are explicitly designed to be mutable. I don't know how functional languages are compiled and maybe somebody who does can chime in, but I would not be surprised if the IR already was imperative. So it may be easy to give some access to that in a language. I'd say "pure" is if the calculation can be done with a function without side effects and it is a deliberate choice to restrict a language to (almost) only that. No side effects at all would mean no interaction with "the outside world" and no access to input data though.
- zelphirkalt 4y agoWe can see FP as a tool to for us to express a functional thought so that the computer can understand it and will translate it into something the computer itself can run.
- kaba0 4y agoHaskell compiles down to C- first, which is an even less expressive version of C basically, so you are right there. But if you go low enough FP concepts pop up again, e.g. out-of-order execution is pretty functional, but to a degree so are vector instructions. And this is no surprise, Turing machines and lambda calculus (and recursive functions and anything Turing-complete) are equivalent. If you think about it, a Turing machine is just as side-effect free in itself, side effects are special to computers.
- jeffreygoesto 4y agoDeep down it must be, as the data is conveyored past fixed compute engines (which can be seen as pure functions), right? FPGA programming is pretty much functional as well. RAM is capturing the state there.
- efnx 4y agoIt’s not that it’s good or bad - mutation can only happen in a monad (IO or ST or similar). The monad is the encapsulation and that encapsulation is enforced by the type checker. It’s actually quite liberating not having to worry about what’s “right or wrong” and instead just do whatever you like that compiles. I suggest getting started with Haskell through http://www.learnyouahaskell.com/ http://www.learnyouahaskell.com/ - it was my favorite.
- galaxyLogic 4y agoI'm looking at it not from the perspective of "Which language is the best?" but from the point of view of I'm working in a specific language now, what are the principles of "Pure FP" that I could benefit from when using that language. How should I "encapsulate state" in JavaScript for instance? If the principles of FP are great surely they must be applicable in any Turing-complete programming language. The (Haskell etc.) compiler is no doubt a great tool, great at type-checking. But I see using any specific compiler or type-checker as a tooling issue, not a foundational insight about FP.
- efnx 4y agoAh yes, indeed there are benefits that come from programming in Haskell that can be applied to JavaScript, but I think that without the compiler it’s very hard to guarantee success.
- amelius 4y agoYes, but the point is that you can fully isolate any part of the program from having side effects. I.e., the caller is responsible for executing its callee's side effects.
- galaxyLogic 4y agoRight therefore it would seem that it is ok to mutate local variables inside a function anyway you want, because that can not have side-effects outside of the function. Right?
- grumpyprole 4y ago> I thought (from what I've read so far) that "no mutable state" is the definition of "pure FP". It's much more nuanced than that, certainly no arbitrary and unchecked mutable state is. There are ways though of achieving mutable state whilst maintaining referential transparency.
- throwaway858 4y agoThat is not the definition of FP. There is no definition of what FP is that is agreed upon by everyone, but the key is the word "functional" in FP. This comes from a mathematical function, which is a mapping of input values to output values. You could write a definition of a function f(x) to be such that the value of f(x) is the result of the execution of some imperative-looking code (including loops that mutate variables). Mathematicians would be satisfied with such a definition and would confirm that f(x) is a function just as valid as any other. And so functional programmers should also accept such a function. In fact, Haskell has specific syntactical support ("do" notation) to allow you to write functions using imperative-looking code including mutations (the ST monad, or other State monads).
- galaxyLogic 4y agoA "function" is a "function" if it always returns the same result for the same arguments, right? Now I'm trying to wrap my head around how can I call a function which takes no arguments but which returns a value the user entered on the keyboard? How can I write a function which returns the current mouse-position on the screen, while still abiding by the functional principle of same result for same arguments always? Can it be done? If not can we still call it "functional"?
- throwaway858 4y ago> A "function" is a "function" if it always returns the same result for the same arguments, right? Yes. This matches the definition of a mathematical function that I gave above. > how can I call a function which takes no arguments but which returns a value the user entered on the keyboard? You can't. If your language allows you to write such a function then I would argue you are no longer doing FP (at least in this part of the code). I believe that this is why many people like languages like Ocaml, F#, Scala. These are hybrid functional-OOP. You can use FP for the parts of the program that it's suitable for, and OOP/mutable-imperative for the other parts("the best of both worlds"). The purist FP programmers might claim that reading input from a keyboard is "uninteresting" and that programming is really about logic, algorithms, and computation, and therefore FP is enough for them (...in their ivory tower). I personally am a fan of Haskell, but I don't like calling it FP, because it does allow you to write "code" that reads input from the keyboard. They still claim to be pure FP by using a loophole and saying that "getLine" is not a "function" but rather an "IO action". But to me it doesn't matter what you call it, you are still effectively allowed to write code that does I/O and mutates external stuff, doesn't matter if you call it a "function" or something else. Of course the big advantage that Haskellers claim is that the language enforces the separation of effectful code from "pure" functions. In the other hybrid FP languages it is possible (and happens often) where you have a deep call chain of "pure" functions and then you realize you need some small side-effect somewhere, so you just add it. Haskell does not allow this at the language level, and forces you to refactor your code. In my opinion this does lead to cleaner architecture and more maintainable code in the long term. But to me Haskell is really interesting for a different reason. I don't like to call it an FP language, because like I said, a lot of the code you write isn't really "functional". A better name would be: "mathematical oriented language". And by math I mean that the code is built using logical systems that have mathematical rules that can be reasoned about. Going back the I/O (reading input from the keyboard): what the Haskell people have done is realized that you can actually model this behavior of user input as a mathematical model. This unlocks a type of thinking that allows you as the developer to go beyond the thinking of telling the computer: "do this, then do this, then do this, if this happens then do this, ...". An example: the mouse-position on the screen. There are haskell libraries called FRP that model the mouse position as a "signal function" (a well-defined term they invented) that is a 2D coordinate that changes over time. You can then combine this signal function with others to create behavior such as an image that follows the mouse. You can build complete GUI applications using this approach, and the code looks nothing like imperative programming, and more like an electric circuit of different components connected together. And that is just one example. The Haskell community has also come up with mathematical models for streams (think unix pipes) that allows you to write streaming code that is much more powerful and cleaner then what you see in other languages. So my summary: Yes, functional programming is limited, but if we go one level deeper, we could say that the essence of FP is really mathematical thinking. And if we embrace that and run with it then we can open up entirely new possibilities.
- agentultra 4y agoPurity is a poor word. It refers to referential transparency: if I give you an input to your foo function, “A”, and I get an output, “a”, then I can always substitute foo “A” for ”a” in my program and it will not change the meaning. It’s poor because it invites other meanings: some people think purity means immutability for example; but that’s only part of it.
- lgas 4y agoThere is no one definition of "pure FP". Everyone has their own.