4 ms·
Becoming fluent in using all the different ways to iterate over traditional collections (map,flatMap, fold, reduce etc.) already takes some time. Extending that
by valzam 5y ago
Becoming fluent in using all the different ways to iterate over traditional collections (map,flatMap, fold, reduce etc.) already takes some time. Extending that to things that programmers don't normaly think of when they think "loop over something" is definitely a hurdle. It doesn't help that these operations have very generic names.
That being said, once you get used to it it is extremely convenient to just map over any sort of "container" and focus on business logic. The above concept even extends to async programming. You can do things like iterating over a Future and let the runtime handle waiting for the value. Functions returning a Future or a Promise can be composed just like you would iterate over a list.
asyncDbOperationGetUser(userId).flatMap(user => asyncDbOperationGetPosts(user.friends))
There are of course different ways of achieving this (async/await) but the power of learning FP concepts is that you can apply the same fundamentals to almost everything that has a defined notion of iteration (--> is a monad).
- dnautics 5y ago> It doesn't help that these operations have very generic names As if "for" and "while" aren't generic names. They're so interchangeable that ziglang has basically replaced C's "for" with "while". And with imperative loops, you have to reconstruct in your mind the state of what you're looping over and remember all possible variables closed over the loop and how they could be in flight during the loop. Map is basically declarative: "this thing is going to happen to each thing in your list"; Reduce is like a for loop, except you explicitly declare what you have to keep track over through the loop. The advantages should be clear.
- valzam 5y agofor and while aren't generic in the context of collections. It's very obvious what for item in itemsList: doSomething(item) means. In any case I think map etc. are perfectly ok but it gets tricky when you talk about Options, Futures, Either etc. since I would argue most people don't immediately see how "looping" (I know it's not really looping) can apply here.
- dnautics 5y agoNot all FPs have options, futures, either (lisp, Julia, erlang, elixir)
- patrick451 5y agoEh. It reminds my of writing vectorized mathematical code in numpy or matlab. Oh it's so much cleaner because you don't have an ugly loop! If all you have is a basic dot product, sure. But a lot of times, a loop is a hell of a lot easier to understand, even if it is slower. Almost universally, I find the map/reduce/filter idioms to be inscrutable, write-only code compared to a good old loop
- dnautics 5y agoHere's some real code from our work system (variable names have been changed): invoice_id |> Audit.get_entries() |> Enum.map(fn entry -> entry.action end) |> Enum.map(fn action -> to_string(action) end) |> Enum.join("\n") Tell me you can write that as an "easier to understand" set of loops. Tell me that this code is "write-only" and that you don't immediately understand what is happening, without even knowing the language it's in.
- valzam 5y agoThe pipe operator really is elixirs secret sauce. The whole OTP platform amazing but web servers can live without it. But the developer ergonomics of the pipe operator for code that is to a large extent 1) accept input 2) parse input 3) transform input 4) store input Is just amazing
- patrick451 5y agoYes, I'll go ahead and say that. I have no idea what this does. It would be a lot clearer as loops.