3 ms·
What is it about pure functional that makes concurrency much easier? Is there a code sample that would illustrate it? I've done both Haskell and Erlang/Elixir
by ramchip 4y ago
What is it about pure functional that makes concurrency much easier? Is there a code sample that would illustrate it?
I've done both Haskell and Erlang/Elixir and yet I don't really see what you're referring to concretely. There was hope that automatic parallelization would be a big win for pure functional, but I don't think it's really worked out in practice, because of the overhead and difficulty of predicting if parallelizing something would make it faster or slower.
- valenterry 4y agoIt's not about performance as much as correctness and easiness to understand code. Functional programming removes the need to simulate (local) state in your head when trying to understand what code does. And in the places where it is inevitable, it makes it explicit and leads to a design where it's easy to track why and how things got changed. For example, .map and .filter are now in almost every language, because they are much easier than for-loops. You see them and you know "aha, this collection will be transformed, the number of elements stays the same" or "this collection will be filtered and the elements will look the same, but some might be gone and no new ones will have been added". Pure functional programming is similar, just that the scope is suddenly "the whole runtime/machine" instead of "a small piece of code that somehow does a loop".
- ramchip 4y agoIf I understand correctly, you're saying Erlang/Elixir code would be easier to understand and work with if functions that did I/O or message passing etc. were labeled as such, via type info. I don't entirely disagree, but I also don't think it would be a game changer for a couple reasons... - It's already well established practice to separate pure and impure modules in Erlang/Elixir projects, even without a type system to enforce it. Take Ecto for instance, it has a clean split of side-effects (Ecto.Repo) and pure logic (Ecto.Changeset). Very different from things like ActiveRecord or Django ORM. [1] - BEAM programs (and libraries) use a lot of concurrency and message passing, and I think you would have to use an escape hatch ala unsafePerformIO more often than a typical Haskell program, otherwise the IO would "infect" most of the code. Things like instrumentation, fetching app environment, calling the code server, using process dict... Joe Armstrong kind of mentions the latter problem in his thesis [2]: Notice that I have chosen a particularly simple definition of “dirty.” At first sight it might appear that it would be better to recursively define a module as being dirty if any function in the module calls a “dangerous” BIF or a dirty function in another module. Unfortunately with such a definition virtually every module in the system would be classified as dirty. The reason for this is that if you compute the transitive closure of all functions calls exported from a particular module, the transitive closure will include virtually every module in the system. The reason why the transitive closure is so large is due to “leakage” which occurs from many of the modules in the Erlang libraries. We take the simplifying view that all modules are well-written and tested, and that if they do contain side-effects, that the module has been written in such a way so that the side effects do not leak out from the module to adversely affect code which calls the module. He is of course talking about "dirty" _modules_. Working at the function level, the leakage wouldn't be quite as bad... but I think it may still be enough to limit how useful IO annotations would be. Code that "has been written in such a way so that the side effects do not leak out" is quite common on BEAM. Who knows though. Maybe we'll see interesting things in Gleam in the future :) [1] "To spawn, or not to spawn?" is a good article on the practice of separating I/O (GenServer) code and pure code: https://www.theerlangelist.com/article/spawn_or_not https://www.theerlangelist.com/article/spawn_or_not [2] https://erlang.org/download/armstrong_thesis_2003.pdf https://erlang.org/download/armstrong_thesis_2003.pdf
- valenterry 4y ago> If I understand correctly, you're saying Erlang/Elixir code would be easier to understand and work with if functions that did I/O or message passing etc. were labeled as such, via type info. No, not quite. Pure functional programming is a specific style or paradigm. It's about writing referential transparent expressions only. Tagging something is "impure" is absolutely not the same, even though doing so and/or separating pure and impure functions is a good first step on the way to pure functional programming. > Who knows though. Maybe we'll see interesting things in Gleam in the future :) Would be nice and might make me switch ecosystems. As of now, there don't seem to be concrete plans: > Yes, Gleam is an impure functional language like OCaml or Erlang. Impure actions like reading to files and printing to the console is possible without special handling. > We may later introduce an effects system for identifying and tracking any impure code in a Gleam application, though this is still an area of research.