24 ms·
Functional Programming – How and Why
- tabtab 4y agoA critique of FP per "mainstream": https://www.reddit.com/r/DilbertProgramming/comments/qg99f0/functional_programming_is_dysfunctional_givvitup/ https://www.reddit.com/r/DilbertProgramming/comments/qg99f0/... (The title is sensationalist, the opinion more nuanced.)
- Vanit 4y agoI mean, in an example where the problem and solution is well understood, sure, but like all things there are downsides and you need to consider appropriateness. Firstly if you're conceiving a novel algorithm it can be tedious to debug/test if written in a functional style because it's hard to step through in the debugger. Second, you need to be extremely familiar with the language and ensure that you know that you're not mixing and matching mutable and immutable system calls, which will be hell to debug, see 1. I'm not anti-functional and sometimes it can yield really clean and easy to read code, but I have to recoil when I see praises sung without the criticism.
- weatherlight 4y agoYour first point, I'm not sure that is true. If you are using a functional style in a language that supports side effects, its still pretty easy to debug. you could implement a tap function that console logs the value, then then returns the result of the previous function in the composition/chain. If you are using a lazy evaluated language like Haskell, instead of the stack trace you're used to in an imperative programing language, you'd get the reductions that led up to the reduction of the expression with the breakpoint on it. The second point, However, I do agree with, especially in languages where mutability is the default.
- steego 4y agoI’m a functional fan and I don’t disagree with your points. Like anything, real life functional programming is not a panacea and most languages that append functional constructs as an afterthought often come with a price (debugging, performance) and just as you pointed out, mixing functional code with imperative code indiscriminately can yield wonderfully nuanced bugs. With that, I find languages like OCaml and F# provide a great ergonomic experience for writing both functional and imperative style code. (There’s nothing wrong with imperative code confined to the scope of a function or a well defined object) Even with great tools, I still think there’s quite a bit that can be done to improve the hidden costs incurred from a functional-first approach.
- galaxyLogic 4y ago> There’s nothing wrong with imperative code confined to the scope of a function Thhat is a fine point which I rarely see discussed in connection with FP. (Pure) FP is commonly understood (?) to mean that there can be no mutable data. You can "bind" a value to a variable but only once. Right? But within a function you can have local variables. I don't see why it would be bad to assign multiple different values to the same local variable, which only exists during the execution of the function. The variable only exists in the "stack" not in the "heap" and is gone as soon as the function returns. So if I run a while-loop and repeatedly assign a new value to the local variable "i" for instance, would that be unacceptable according to "FP"? Why? I can't see any ill effects from modifying a variable whose value can not "linger" past the execution of the function. What am I missing? Why is it (supposed to be) bad to rebind any number of different values to a local variable?
- grumpyprole 4y agoPure 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.
- josephcsible 4y ago> ensure that you know that you're not mixing and matching mutable and immutable system calls Languages that were designed from the ground up to be pure functional, like Haskell, keep you from making this mistake.
- throwawaymaths 4y ago> Second, you need to be extremely familiar with the language and ensure that you know that you're not mixing and matching mutable and immutable system calls, which will be hell to debug, see 1 How is this not the case, for say, python? E.g. You can get yourself into real trouble with a function like this in python. def f(dict = {}): return dict
- lgas 4y agoIndeed. It's actually easier in languages like Haskell because the type system won't let you mix and match.
- throwawaymaths 4y agoI mean, if you then use the result of f in a mutating function, the default value will be mutated the next time you call it
- lgas 4y agoRight, but the point is that you can't actually write the equivalent of that function in Haskell. You'd have to write something like this: defaultMap :: Map k v defaultMap = ... f :: TVar (Map k v) -> IO (Map k v) f = \case Nothing -> newTVarIO Map.empty Just m -> pure defaultMap which would make it hard to be unaware of the possibility that the dictionary you get each time you pass `Nothing` would be the same one. And then the type signature returns an IO action, so you would know that "anything could happen here", whereas there's no such indication in python. Conversely, if you had your `f` function in Haskell has a type like `Maybe (Map k v) -> Map k v` then you know that it can't possibly be creating a mutable map and inserting it in the process somewhere without your knowledge. (Modulo `unsafePerformIO` and other evils like that).
- shay_ker 4y agoCan anyone elucidate why code written in a functional style is harder to debug?
- eyelidlessness 4y agoI’m fanatical about functional programming, and I would never choose this example to demonstrate why I am. The imperative code doesn’t demonstrate any kind of problem (see Rich Hickey’s explanation of transient types), and the functional code demonstrates how but not why. I’d certainly use a modified version of this example where the inputs might be mutated by other parts of a program. But without that, this is just philosophical navel gazing pretending to explain how to solve mysterious problems.
- jemmyw 4y agoThe example given isn't really functional programming is it? Or am I missing something? In those examples you start with an object, call a method on the object returning a new object, then call a method on that and so on. I like this kind of chaining in OOP. Languages like JavaScript and Rust (and Go?) have blurred the lines between purely functional and purely imperative. I think I prefer that compromise position myself.
- brundolf 4y agoMethod vs non-method calling syntax is a red herring; a method is just a function where you put the first argument on the left instead of inside the parenthesis Hanging functions off of objects/types isn't really anti-functional either, as long as they don't mutate the subject Functional programming is mainly about not changing state; you can do that with or without methods
- jemmyw 4y agoWell there's a certain anti functional feel to it because your functions are tied to the object rather than being able to process any given object or objects of different types. Difference between functional style and functional language?
- brundolf 4y ago> rather than being able to process any given object or objects of different types Not necessarily- the functions can still be polymorphic. Rust does a particularly cool thing here, where any struct or trait method can be called in non-method syntax (or even passed as a first-class function!). I believe Julia also has type-based polymorphism while still being considered a functional-adjacent programming language. And then there are other languages where any function in scope can be called in method syntax, without being explicitly associated with the value's type (there's a name for this feature but I can't remember it) > Difference between functional style and functional language? I don't know the precise definitions well enough to distinguish them (though I'm not sure they have precise definitions)
- michaelteter 4y agoTiny examples like these really don't demonstrate the big benefits of FP. However, they do illustrate the altitude of approach to problem solving. In the imperative solutions, the programmer is essentially thinking and acting like a problem solver AND computer. There's the human element of understanding the problem and devising a solution, and then there's the step-by-step implementation. This is fine, and it's quite good for learning how to think. But it doesn't take much experience to ascend above it... The FP solutions illustrate a problem solver "telling" the computer what operations to perform on a dataset to get the result. At first even the tiny FP example may be off-putting to someone from an imperative background. It may seem a bit obtuse. But really, it is just thinking about the major steps necessary to transform one set of data into another, and then knowing which tools/building blocks to use to achieve that goal. You intentionally stop caring about how to add elements of a list together and instead just choose the right functions to map/apply/(reduce) your data with. Now what I have not yet wrapped my head around is the Clojure transducers. I get the concept, but haven't quite grokked it fully. They are the step beyond the data.do_this.then_do_this.etc. But for me, FP approaches, even applied to traditionally imperative languages (even Python, with some struggling with inconsistent and unergonomic details) provide some key benefits. 1. Pure functions can be understood and then forgotten about; once you know what it does, your mind is free to never worry about unexpected things going on inside. This is counter to typical OO functions which mutate objects at will. The mental load is so much higher with the OO mutation functions. 2. Pure functions are vastly easier to test. Couple this with using simpler, decoupled data types (hashmaps, arrays, structs... things which generally do not require special setup and teardown due to instance creation activities) and you have a much easier time writing tests that cover 100% of lines/branches - in fewer lines of code than incomplete OO tests. All that said, I am less enthusiastic about passing anonymous functions everywhere as is common in modern JavaScript. That increases the cognitive load for me simply because it's harder to remember what does what and where things are happening. So I try not to have more than 1-2 layers of functions passed to functions. There is one FP-related challenge which doesn't really have a solution as far as I can tell: more small functions means more function names to think of. To keep them recognizable and memorable, the names must be pretty descriptive. This means you can end up with some_pretty_long_function_names. It's a small concern, however. And as a bonus, your code ends up reading a lot more like human language - meaning you can give a code tour to a less technical person and they may actually be able to follow.
- mirekrusin 4y agoFunctional combinators over generators (output) and iterables (input) works well for this type of problems, including ts type safety ie. [0]. We use it in production in many places and works well for years for us. [0] https://observablehq.com/@mirek/project-euler https://observablehq.com/@mirek/project-euler
- whatever1 4y agoFP feels neat, but good luck debugging it.
- Jtsummers 4y agoWeird. Functional code is usually easier to debug in my experience because it's based more on composition so you can test components much more easily and isolate error causing sections. It's a lot easier than a 1k SLOC C function (or even 100 SLOC one) where you have to use a debugger or introduce logging (printf debugging) to try and isolate the error.
- Eji1700 4y agoYeah this has generally been my experience with f#. On top of all that runtime errors are way less common because the compiler catches so much more
- whatever1 4y agoFP hides the individual elements behind neat functions. If you are investigating to find a single outlier that broke your program, you need to examine the data points one by one.
- Jtsummers 4y ago> you need to examine the data points one by one. What does this phrase mean? And yes, FP promotes "neat functions". Which isolate behavior and consequently means they can be individually evaluated and evaluated in combination with each other to find the error. It's not a hard problem. And much easier than the 1k SLOC (or worse, several 10k SLOC) C functions I've had to debug in my career. I have repeatedly reduced that kind of garbage down to 10-20% of the original code by applying a functional style and decomposing the horrendously complicated logic into something sensible and, wait for it, debuggable. Why was it debuggable? Because unlike the original it was comprehensible.
- whatever1 4y ago
- logicallee 4y agoI'm curious about something. Is the time a functional program takes to run considered a side effect? You might think that in metaprogramming to generate a program you just care about the program you receive - it is a pure function, right? But there's a difference between waiting around for a long time for the result versus getting it instantly.
- eyelidlessness 4y agoYes, the passage of time is a side effect. If your functional program is measuring the passage of time, it must accept time-elapsing arguments which are independent of its computation. If its own computation’s elapsed time is part of the computation, that’s inherently impure. That’s okay, but it’s a limit of functional programming purity. If you’re not measuring the function’s own passage of time but rather time passing as a concept, you can just pass arguments to the function which satisfy that interface and test how it’ll behave. That’s what’s awesome about FP: time is a parameter to your function like any other, and you can call it with any equivalent thing.
- logicallee 4y ago(I didn't mean a function that measures time passing, I just meant the time that a computation takes.) Regarding my question which you answered, this means there is no such thing as a pure function then, since any function has the "side effect" of making time pass that wouldn't have if you hadn't called it.
- bigDinosaur 4y agoThe time passes whether or not the function is called, calling a function does not cause time to pass. Time also seems to be a pure function: current state of the universe -> next state of the universe, which is neat.
- msla 4y ago> Time also seems to be a pure function: current state of the universe -> next state of the universe, which is neat. Certain interpretations of quantum mechanics would disagree that, if you put a given state of the universe into the "iterate the universe's state" function, you'll always get the same universe out the other end. The idea that quantum state transitions are truly random would foreclose on that.
- ttyyzz 4y ago>Imagine we want a range function where range(5) returns [1,2,3,4,5]. The imperative solution makes perfect sense and is fast, everyone can understand it including future me. I don't have to think about it at all and just understand it as I'm reading it. In the real world out there this is something that carries a lot of value.
- maweki 4y ago> everyone can understand it The recurrence relation of range(n)=range(n-1):n is easily understood and also already the naive functional implementation. These kinds of recursive/recurrence definitions are part of K12 curriculae, and not just at the end of it. Functional programming is not inherently harder to understand than imperative programming. Your school blackboard has been functional and stateless since grade 1. At some point somebody tacked state on to your mental model, and somehow I=I+1 now makes sense. To me it looks like a purely educational problem, when FP is dismissed for not being easily understood, compared to the IP abstractions.
- Liquidor 4y agoSo if I use/chain Object.methods in JS I'm basically writing functional programming? Is that really what FP is? I had the impression that FP was something different.
- Plecra 4y agoYep! If the methods create new objects, and leave the method arguments unchanged, you'll likely be writing code that's vaguely functional.
- IshKebab 4y agoYeah just functional programming isn't that mind-bending IMO. F# and OCaml are pretty easy to pick up. I think the confusing bit is that one of the most popular functional programming languages is Haskell... which is really hard. So certainly in my mind I had "functional programming = like Haskell = stupidly difficult" for ages. But Haskell is difficult for other reasons: really abstract type system, functions are pure, etc. Oh also another thing is they all tend to really encourage you to use immutable singly linked lists and write recursive functions that match on (head :: tail)... but I don't think you have to do that, and IMO it's the wrong thing to do a lot of the time (it semantically nice but computationally terrible).
- gherkinnn 4y agoAt its core, FP is programming using only functions. The rest follows.
- MrManatee 4y agoNot all functional programming idioms work in all languages. On my computer, the article's imperative range(6000) took 0.05 ms and the "functional" range(6000) took 400 ms. The whole [...cur, cur.length+1] thing turns a linear algorithm into a quadratic one. It wouldn't happen in all languages, but that's how JavaScript's arrays work. My advice is that if you really want to do stuff like this, choose appropriate data structures (i.e., learn about persistent data structures). Except in this case the imperative version is already totally fine. It is modifying an array that it created itself. You have all of the benefits of avoiding shared mutable state already. Also, the difference in performance would become even worse, except that for range(7000) I already get "Maximum call stack size exceeded" on the recursive one. The imperative implementation handles 10000000 without breaking a sweat. My second advice is to not use recursion to process arrays in languages (like JavaScript) that have a very limited call stack size.
- onsclom 4y agoGreat points! I am still trying to figure out how to best use functional programming with JavaScript. I've found writing performance critical parts imperatively while being conscious about shared mutable state is a decent compromise. > My second advice is to not use recursion to process arrays languages (like JavaScript) that have a very limited call stack size. Can also confirm this, here was my process on the some of the harder days in Advent of Code: 1. I wonder if I can solve this in a pure functional style with JavaScript 2. Yay, it works on the example input 3. Oh, I hit the call stack limit on the real input 4. Time to rewrite the recursion as a loop lol
- toastal 4y agoShame since ECMAScript 2015 was supposed to give of proper tail calls in JavaScript, but Blink chickened out and so did Gecko.
- VaxWithSex 4y ago5. refactor loop as loop function
- mixedCase 4y ago
- onehair 4y ago> Why use functional programming 4. Make most code harder to read
- patife 4y agoliked it
- Mathiciann 4y agoI know the author was only trying to show some benefits of FP but choosing such a trivial example gives a bit of a one-sided view of FP. Try solving the harder AoC problems and you will probably need mutable state (at least I do). Also I am not sure if for example recursion is always the best option when performance becomes a factor.
- zelphirkalt 4y agoI solved the first 13 days mostly in functional ways [1]. The 2 not functional things I used were arrays and hash tables. OK and outputting things ... . For arrays I wrote a functional map function, since my language did not have a functional one and I only used it for transforming input, while preserving the original input under a different binding. For hash tables I could have used functional sets, which I only bothered with in later puzzles, because I wanted to parallelize things. I did parallelize quite a few things in later puzzles, just because it is so easy to do when you have pure functions. So at least 26 of 50 puzzles are perfectly possible in functional style. [1]: https://notabug.org/ZelphirKaltstahl/advent-of-code-2022 https://notabug.org/ZelphirKaltstahl/advent-of-code-2022
- cronin101 4y agoYMMV but each year I use Haskell to solve AoC and I've never needed mutation or any particularly intensive `IO/State` Monad trickery to get any day completed regardless of how far into the challenge it goes. Part of the charm of purely functional solutions for me (and why I'm hooked) is that it forces you to think about the representation of the data that you would need in order to have a "clean" solution without mutation. E.g. IntMap for index of arrays and folding with Set/Map operations to build state without accruing algorithmic complexity. I've found that I do a lot more "deep thinking" when forced into using (or creating) the right data-structures and this is something I enjoy a lot more than purely iterative debugging/hacking, and it's more satisfying (to me) at the end of it all. My go-to for AoC is almost always Attoparsec + Containers with a recursive "solve" function and the complexity seemingly always stays manageable. I'm no savant but feel free to give examples of a tricky task to solve functionally I can share a specific solution.
- shireboy 4y agoI get why functional programming, but why functional languages? The article uses JavaScript. I do c# professionally, which can do similar, and have only dabbled in f#. Seriously asking so I can understand better: what can f# do that c# can’t?
- rowls66 4y agoMore importantly is what functional languages leave out or restrict. Imperative languages can add functional language features, but functional purity is not enforced, the full benefit of functional programming is not realized.
- mjburgess 4y agoExpress programming concepts without 12 keywords
- Mathiciann 4y agoHigher order functions, currying, discriminated unions and using pipelines to start with. I guess all concepts are technically possible in C# but the language is not really designed for it.
- deleted 4y ago[deleted]
- porcoda 4y agoIt's not a question of what one can do that the other can't. They can both achieve the same thing (they both map to CIL after all). It's usually a question of ergonomics - how much work do you want to put in to achieve the same goal. Things like algebraic data types (discriminated unions in F# speak), currying, etc. all are just a matter of making the compiler do some things that you'd do by hand in a language like C#. While you can accomplish the same thing in C#, languages like F# do it for you so you get both ease (compiler does the work) and correctness (compiler not likely to mess up where you might by hand). I bias towards the F# world for the ease and correctness reasons, but there's nothing stopping a careful programmer from achieving the same thing in the C# world.
- zelphirkalt 4y ago
- tkrskxyz 4y ago>Avoid bugs related to mutable state. And generate a lot of overhead both in execution time and memory. Which is unacceptable in games where every ms counts. >Games tend to define update() functions which mutate some state each tick. We can avoid mutation by taking game state as an argument and returning new state. Now our game is much easier to test too! We simply call update with some game state and assert that the result is what we expect. Imagine how hard it would be test the imperative update function! As a game dev I kinda cringe on the idea of copying WHOLE world state just to update it (and if I understand correctly we copy the state EVERY TIME we want to update i.e: from every actor instance?).
- henrydark 4y agoNot to disagree, but to be fair modern fp runtimes use data structures that wouldn't have to copy so many bytes as the whole state. A nice showcase of this idea is in Juan Pedro Bolivar Puente's CppCon '17 talk Postmodern Immutable Data Structures: https://youtu.be/sPhpelUfu8Q https://youtu.be/sPhpelUfu8Q
- zelphirkalt 4y agoOn the other hand it is kringe-worthy, when people use mutable state and then are unable to properly parallelize the workload onto multiple cores. I mean, if I understand correctly, we have many cores sitting around and only 1 is working? Sometimes also a few, before we hit the bottle neck of mutual exclusion.
- AnimalMuppet 4y agoOn the other other hand, if you've got a game state, and you want multiple cores to do the update, and you're not using mutation, then when core 1 makes a change (from state 0 to state 1, say), then when core 2 makes a change, it has to start from state 1, not from state 0, so that core 1's change doesn't get lost. So then you have the problem of updating all the cores (and all the threads) with state 1 before any of them make any further changes. The way I would do this imperatively with N cores is, I would have the game state be an array, and I would have each core update 1/Nth of the array. That might thrash the cache, but it wouldn't need any locking at all. Functionally, it could probably be done better to have each core produce a new sub-state, and then have one thread combine the N sub-states into the new state, and update all the threads with the new combined state.
- amelius 4y agoFunctional programming is like having container-technology right in your programming language. I.e., you can fully contain anything that a called function does. It is immensely powerful.
- deleted 4y ago[deleted]
- lofaszvanitt 4y agoI never would've thought religion will be a thing in programming.
- TchoBeer 4y agoThen you haven't been paying attention. It's always been like this.
- mckravchyk 4y agoI was trying to evaluate FP one time, try to get it, but I can't envision using it in a pretty complex front-end where many things inter-depend on each other. With imperative programming I can easily step through the code and reason about the flow of execution, looking at FP, I can't help but think the codebase would become very hard to reason about and extend. Side effects are inevitable so if you are going to have side effects in a monad, what's the point anyway, one way or another you have side effects. Unit tests may be easier, but it's still trivial to do mocks. Mutability? I'm using a custom map type for global state entities that helps me deal with it and I'm also very mindful whenever I assign anything to an object property (in JS). I respect FP, but I don't envision using it personally, and by the way, I don't get how OOP is getting bashed on HN so much. Like google FP + HackerNews and there are articles about FP like this one, google OOP + HN and you get "OOP is not just bad, it's super-duper-hyper-ultra atrocious".
- valcron1000 4y agoI suggest trying to build an app using Angular and just observables to handle all state + interactions. In my experience, it's the best way to build an UI where "many things "inter-depend on each other". It's on a whole other level compared to using React with `[name, setName] = useState("")`
- deleted 4y ago[deleted]
- kephasp 4y agoMy team builds frontends in Elm and backends in Haskell and we experience the opposite: FP made the code very easy to reason about and plugging things together is easy too.
- consilient 4y ago> Side effects are inevitable so if you are going to have side effects in a monad, what's the point anyway, one way or another you have side effects. Imagine a style of programming where everything is assumed to be asynchronous, all the way down to language primitives. Someone who only ever wrote AsyncScript would look at TypeScript, say "Requests are inevitable, you're always going to end up in async/await anyway, so what's the point?" This is exactly the relationship between imperative and pure-functional programming: the point of having explicit effect monads (or some other tracking system) is that it makes it possible to write code that isn't in them.
- account-5 4y agoI quiet like declarative code. SQL, regex, and recently XLST just seem to click in my head. It's like telling the computer what output you want. Like providing the output scaffold and leaving the computer to fill it. The more I read about functional programming the more it seems like that. Am I correct in my assumption? Is functional programming declarative? Is all functional programming declarative? APL seems a little like this from my research. The thing that confuses me is that under the hood isn't the computer doing those loops? It's just hidden from you?
- dkarl 4y agoDeclarative versus imperative is sometimes in the eye of the beholder. Helping a C++ friend of mine with some Scala code the other day, there was a line like this: val requests = availableDrivers.filter(notPhonedHome).map(pleasePhoneHomeRequest) When I explained filter and map to him, he thought of them as imperative. "Okay, filter loops over the array of available drivers and collects the ones that haven't phoned home in a new array. Then map loops over that array, creates a status notification for each one, and collects them in another array." I thought of this line in a more declarative way: requests is a list of phone home requests for the drivers that haven't phoned home recently. Both of us used a simplified mental model that didn't fully reflect what the computer is doing. My model didn't account for memory allocations. His model didn't account for potential optimizations. Neither of our models accounted for type-level trickery, possible side effects of pleasePhoneHomeRequest, or error handling (although his was closer to accounting for side effects and error handling.) Does the intermediate array actually get constructed? What happens if pleasePhoneHomeRequest throws an exception? Is requests a concrete collection type, or is it something akin to an iterator? In practice, a language like SQL has similar concerns. Occasionally you may need to be aware that an awkwardly constructed query requires space that exceeds the size of the relevant data, or that a delete cascades in a way that is inherently slow. tl;dr Functional programming idioms are designed to let you think more declaratively when you read and write code, but sometimes the declarative view isn't adequate for understanding the code.
- valenterry 4y agoNo it is not. Functional programming (at least before the term got watered down) is all about referential transparency, which has some major implications of how you read and write code, e.g. allowing to apply equational reasoning and making effects explicit. Because it requires some more abstract concepts to be practically useful, you will also see the same people tending more in the direction of declarative programming - but strictly speaking the two things are independent of each other. > The thing that confuses me is that under the hood isn't the computer doing those loops? It's just hidden from you? No. Under the hood the computer is doing conditional jumps. And yeah, those are hidden from you. :)
- gilbetron 4y agoI've done about a hundred coding interviews in the past couple of years, and one thing I've noticed is that unless you are really, really good at functional programming, don't do functional programming in an interview. Many people try it, because they think it is more impressive or proper or whatever, and then it doesn't work correctly, and they flounder because debugging within a functional idiom is different, if not more difficult. Then they switch to imperative, and things get better. I've seen maybe 2 or 3 people that can handle debugging when using the functional approach. As a side note, those 2 or 3 were not any more or less capable, in the end, than other interviewers. I don't quite know what to do with that datapoint, but it is interesting.
- ericlewis 4y agoI did this, but practiced like crazy before the interview since I knew what we would be building during interview.
- bennysonething 4y agoBiggest thing I got from functional programming: avoid state if you can. Sometimes functional style isn't as clear (especially recursion for me). But things like map and filter are usually a lot easier for me to read than for loops.
- AnimalMuppet 4y agoEspecially, avoid shared mutable state if at all possible. That's the biggest thing I got from FP, too. FP says that shared mutable state is evil, and FP is absolutely right about that.
- manv1 4y agoRecursion in production code? Say it ain't so...
- gherkinnn 4y agoIn this example, I would start with the FP solution because that's how I happen to think. Probably familiarity bias, but I find the cognitive load much lower. If performance becomes a problem (it might, after all there are several more passes than strictly necessary), have tests in place and refactor to an optimised imperative version.
- pixel_tracing 4y agoI understand this “looks cleaner” but we should really understand what the transpiler or compiler is doing behind the scenes. Functional code like this might introduce bottlenecks in performance. In some languages the imperative for loop is the most efficient way to iterate, sometimes the compiler does optimize functional code into imperative code