[HN Gopher] What's so great about functional programming anyway?
       ___________________________________________________________________
        
       What's so great about functional programming anyway?
        
       Author : redbell
       Score  : 334 points
       Date   : 2022-11-16 08:34 UTC (14 hours ago)
        
 (HTM) web link (jrsinclair.com)
 (TXT) w3m dump (jrsinclair.com)
        
       | gehen88 wrote:
       | I read the whole thing waiting for the aha-erlebnis which never
       | came. I'm a full stack JS/TS engineer with a decade of
       | experience. I expected this article to be written for someone
       | like me. It didn't click, even though I already love and use
       | functional aspects like immutability and pure functions. I feel
       | like it's the whole new set of terminology that puts me off (and
       | I'm talking about `scan` and `Task`, not even `Functor` or
       | `Monad`). I have confidence I can learn and apply this in a few
       | weeks, but I can't realistically expect junior/medior devs to
       | quickly onboard into a codebase like that.
       | 
       | Maybe I'm biased against "true" functional programming because
       | I've been on Clojure and Scala projects in the past (as a backend
       | dev) and both experiences have been good for my
       | personal/professional development, but a shitshow in terms of
       | long-term project maintenance caused by the enormous learning
       | curve for onboarding devs. The article talks about how great it
       | is for confidently refactoring code (which I bet is true) but
       | doesn't talk about getting people to understand the code in the
       | first place (which is still a requirement before you can do any
       | kind of refactoring).
       | 
       | My only hope is for ECMAScript (or maybe TypeScript) to introduce
       | these OK/Err/Maybe/Task concepts as a language feature, in a way
       | which befits the language rather than trying to be "complete"
       | about it. We don't need the full spectrum of tools, just a
       | handful.
        
         | jerf wrote:
         | "I read the whole thing waiting for the aha-erlebnis which
         | never came."
         | 
         | This is increasingly my go-to metaphor for this: This article
         | and many of its kind are talking about bricks. They really like
         | bricks, because they're square, and they come in several nice
         | colors, you can really bash a clam with them, they're cheap,
         | they're quite uniform, they make great doorstops and hold down
         | stacks of paper really well, and they have a personal
         | preference for the texture of bricks over other possible
         | building materials. These people think bricks are great, and
         | you should incorporate them into all your projects, be it steel
         | bridges, mud huts, a shed out back, a house, everything. Bricks
         | should be everywhere.
         | 
         | Then they build you a tutorial where they show how it looks to
         | build a mud hut, and how nice it is to put some random bricks
         | in to it. Isn't that nice. Now your mud hut has bricks in it!
         | It's better now.
         | 
         | But that's not what bricks are about. Bricks are not about
         | textures or being good at bashing open clams. Bricks are about
         | building walls. Walls that may not be the solution to every
         | wall, but certainly have their place in the field of wall
         | building because of their flexibility, easy of construction,
         | strength, cheapness, etc. Trying to understand bricks out of
         | the context of using them with mortar to build walls is missing
         | the point.
         | 
         | Contra the _endless_ stream of tutorials that make it look like
         | functional programming is essentially mapping over arrays and
         | using Result /Option instead of error returns, that is not what
         | functional programming is about. That is a particular brick
         | functional programming is built out of. It isn't the only
         | brick, and if you scan a _real_ Haskell program, isn 't even
         | necessarily one of the major ones in practice. They turn out to
         | be a specific example of a very simple "recursion scheme".
         | These simple "bricks" show up a lot precisely because they are
         | so simple, but generally the _architecture_ layer of the
         | program is built out of something more interesting, because
         | "map" turns out to be a very small and incapable primitive to
         | build a real program out of.
         | 
         | In my considered opinion and experience, if you spend time with
         | "functional programming" and come away thinking "oh, it's about
         | 'map' and 'Result'", the point of functional programming was
         | completely missed.
         | 
         | And stop telling people that's what it's about! You're putting
         | a bad taste in everyone's mouth, because when all the
         | imperative programmers look at your so-called "functional" code
         | in imperative languages and say, "That's a nightmare. There's
         | all this extra stuff and noise and it's not doing anything very
         | useful for all that extra stuff."... _they 're completely
         | right_. Completely. It is a net negative to force this style in
         | to places where it doesn't belong, quite a large one in my
         | opinion. And especially stop being sanctimonious about they
         | "don't get it" when people object to this style. It is the one
         | advocating this style where it does not belong that does not
         | "get it".
         | 
         | The worst thing that can happen in one's education is to
         | _think_ you 've been exposed to some concept when you in fact
         | haven't, and come away with a wrong impression without
         | realizing there's a right one to be had. I still encourage
         | curious programmers to clock some serious time with real
         | functional programming to learn what it is about. This style of
         | programming isn't it, and your negative impressions of this
         | style don't necessarily apply to real functional programming.
         | (It does some, perhaps, but probably not the way you think.)
        
           | Verdex wrote:
           | _Part 1: The request_
           | 
           | Do you have a writeup that you can point me towards that goes
           | into detail about why functional programming isn't about
           | map/reduce/filter and is instead about reconceptualizing your
           | entire program as consisting of recursion schemes[1]?
           | 
           | I'm asking because I've been working with FP languages for 15
           | years now and the first time I've seen this point of view is
           | from your comments. [Although, I suppose you sort of see a
           | half formed version of this in the little schemer and
           | seasoned schemer books. But just not enough so that I would
           | consider it the point they were trying to make sans your
           | comments.]
           | 
           |  _Part 2: Furthering the discussion_
           | 
           | Of course personally, FP isn't a single well formed idea or
           | philosophy any more than a hurricane is a well formed entity.
           | Just a bunch of dust and wind going in the same direction. As
           | with all other programming paradigms. I'm perfectly happy
           | with the true soul of FP being some reconceptualization of a
           | program into recursion schemes because my plan, as with all
           | paradigms, is to pick and choose the individual conceptual
           | motes and mix them together in a way that allows me to best
           | solve my problems.
           | 
           | I actually dislike what I think you're saying recursion
           | schemes are for a similar reason as to why I dislike excess
           | shared mutable references and loops with excess mutation. It
           | places the programmer into a sea of dynamic context that must
           | be mentally managed in order to understand the meaning of the
           | program. Meanwhile, map/reduce/Result, places the programmer
           | into a static reality where all meanings have computer
           | verifiable proofs associated with them.
           | 
           | My version of FP doesn't have recursion or loops. Just
           | map/reduce/ADT and functionality that allows you to convert
           | recursive data into lists and lists into recursive data.
           | Maybe that doesn't make it 'true' FP. Which doesn't bother
           | me.
           | 
           | [1] - https://news.ycombinator.com/item?id=33438320 >
           | Reconceptualizing your entire program as consisting of
           | recursion schemes and operations that use those recursion
           | schemes, what I think the deep, true essence of functional
           | programming as a paradigm is
        
           | [deleted]
        
         | zmmmmm wrote:
         | Always makes me sad that Scala got sucked into the pure-
         | functional priesthood type culture rather than the "better
         | Java, by being mostly functional and immutable and then
         | practical as hell when appropriate" pathway. I _really_ like
         | coding using Scala but the way I like to do it feels totally
         | non-idiomatic.
        
           | piaste wrote:
           | > "better Java, by being mostly functional and immutable and
           | then practical as hell when appropriate"
           | 
           | That's very much what Kotlin is aiming for.
        
           | gehen88 wrote:
           | So true. I was involved in two very different Scala projects.
           | One was the sensible "better Java" way, which was mostly
           | great. The other was a big enterprise project with a core
           | group of "hardcore" FP enthusiasts which was very stressful
           | because of imposter syndrome and troubles to onboard new
           | folks. I have been against Scala ever since, exactly because
           | of this FP cult.
        
             | wiseowise wrote:
             | > The other was a big enterprise project with a core group
             | of "hardcore" Spanish enthusiasts which was very stressful
             | because of imposter syndrome and troubles to onboard new
             | folks. I have been against Spanish ever since, exactly
             | because of this Spanish cult.
        
           | davedx wrote:
           | Scala tried to be too much. Too many paradigms. Too much
           | flexibility and power. Many people might think they want
           | that, but a subset are probably going to have an easier,
           | happier life choosing a less powerful language...
        
         | piaste wrote:
         | > I read the whole thing waiting for the aha-erlebnis which
         | never came. I'm a full stack JS/TS engineer with a decade of
         | experience. I expected this article to be written for someone
         | like me. It didn't click
         | 
         | Don't worry, it's not about you. The article is genuinely
         | underwhelming.
         | 
         | It walks you up the abstraction tree to the building of higher-
         | kinded types, but then just handwaves it with 'and now you can
         | do a lot of things!' but doesn't show them.
         | 
         | It needs a final part where the flexibility is displayed.
         | Something like 'if (debugMode)
         | runpipeline(synchronousDebugWriter) else runpipeline(promise)'.
        
         | davedx wrote:
         | OK/Err/Maybe can be trivially implemented with TypeScript, _if
         | the project development team wants them_. We have it in the
         | current project I work on and it works well with GraphQL.
         | 
         | For OK/Err, in my experience it kind of depends on "how happy
         | is your dev team with using exceptions for general purpose
         | errors"? The orthodox school of thought says "exceptions only
         | for exceptional errors", in which case things like OK/Err give
         | you a nice way to structure your control flow and its typings.
         | 
         | `Maybe` is used by `graphql-code-generator` to explicitly mark
         | optional typings in generated TypeScript types for a GraphQL
         | schema. I don't think it's necessary (TypeScript has `?` after
         | all) but some people prefer it.
        
           | Cthulhu_ wrote:
           | I've used patterns like that in Scala; I see their value in
           | building a correct system etc etc etc, but only if it's
           | consistently used throughout the codebase.
           | 
           | As it stands, most JS/TS projects aren't very consistent to
           | begin with; error handling is either not done at all (let it
           | fail), or a mix of exceptions, failing promises, error
           | responses / types / states, etc.
           | 
           | But that's not really down to the language, more the
           | underlying culture.
        
         | substation13 wrote:
         | > My only hope is for ECMAScript (or maybe TypeScript) to
         | introduce these OK/Err/Maybe/Task concepts as a language
         | feature
         | 
         | When using these concepts the need for do-notation comes up
         | pretty quickly. It would be like using JS promises without the
         | async keyword!
         | 
         | Of course, follow this to it's conclusion and you will have a
         | functional language.
        
           | Cthulhu_ wrote:
           | I mean they could ADD it, just like nowadays individuals can
           | choose to implement it themselves, but it wouldn't supersede
           | any existing error / result implementations (success/error
           | callbacks, throw/catch, promises which use both, etc).
           | 
           | To improve or change a language, I think you should get rid
           | of another feature if it solves the same problem, instead of
           | add another option.
        
             | substation13 wrote:
             | > just like nowadays individuals can choose to implement it
             | themselves
             | 
             | I don't think this is possible with JS right now?
        
         | ravenstine wrote:
         | Maybe I'm wrong, but I think all the talk around weird ideas
         | like Functors, Monads, etc., are mostly red herrings and aren't
         | that applicable to most everyday software engineering tasks.
         | 
         | Just use functions, avoid state, use map/reduce if it's more
         | readable, avoid OOP most of the time (if not all of it), avoid
         | abstracting every single damn thing, and what you're writing
         | seems functional enough even if it doesn't totally satisfy the
         | academic view of what functional programming is.
        
           | PartiallyTyped wrote:
           | > Maybe I'm wrong, but I think all the talk around weird
           | ideas like Functors, Monads, etc., are mostly red herrings
           | and aren't that applicable to most everyday software
           | engineering tasks.
           | 
           | They are a red herring. In most cases, all you need to know
           | about a monad is that it defines some kind of transformation
           | of the enclosed data by applying a function onto it that
           | returns a Monad of the same kind.
           | 
           | e.g. the list monad [a] says that if you bind it with a
           | function f: a -> [b] (ie a function that takes a value and
           | returns a list of b), the monad will transform to [b] by
           | concatenating the lists.
           | 
           | the maybe monad Maybe[a] says if you bind it with a function
           | f: a -> Maybe[b], if Maybe has type Some(a), the data of the
           | monad is replaced by the result of the function. If the monad
           | has type Nothing, then it retains nothing. It's no different
           | to
           | 
           | a = f(a) if a is not None else a
           | 
           | So a monad is just an object that defines the transformation
           | of the underlying data when applying a function that returns
           | a monad of the same type, nothing more.
        
         | fleddr wrote:
         | I couldn't agree more. I feel that some thought leaders
         | debating intellectual concepts in computer programming have no
         | idea how real world software development takes place these
         | days.
         | 
         | Developers are under enormous time pressure to deliver. They
         | face an exponential skill curve as their scope is massively
         | broad (i.e. devops). Things need to be shipped fast, time for
         | "proper" engineering is compromised. Team members working on
         | the codebase are of various skill levels and ever changing.
         | Finally, a lot of products being worked on have a limited shelf
         | life.
         | 
         | For 80% of developers worldwide, the concepts discussed in the
         | article are too steep, and therefore unusable.
        
           | itronitron wrote:
           | I've occasionally watched colleagues give presentations on
           | functional programming over the years, and while I can see
           | why certain people are drawn to it the stated benefits of
           | functional programming have never seemed that significant to
           | me. The advantages that FP provides aren't likely to be
           | needed by developers that are capable of learning it.
        
         | wokwokwok wrote:
         | I've had similar experiences with scala and clojure
         | professionally. I now actively oppose people attempting to add
         | functional code to projects I work on.
         | 
         | ...because when they say "more functional" most people mean:
         | 
         | I want less code.
         | 
         | I want the code to be shorter, because I'm lazy and I want it
         | to be all on one screen.
         | 
         | ...but that's _actively harmful_ to almost any code base.
         | 
         | You want simple code, _not_ dense complicated code. Dense
         | complicated code is for people who wrote the code, and a few
         | smart talented people. Other people have to work on the code
         | too. They cannot.
         | 
         | Actual functional code doesn't strive for code density, it
         | strives for code _purity_ and algebraic structures.
         | 
         | That's fine. Do that.
         | 
         | Dense map reduce reduce flow reduce functions can die in a
         | fire.
        
           | rfrey wrote:
           | I think you're conflating "readable" and "uncomplicated" with
           | "familiar". I'm equally infuriated by OO code with
           | dependency-injected-everything from some hidden framework
           | configured by fourteen XML files somewhere in a different
           | file tree, interfaces for every single class even if only
           | instantiated once, factories to create builders that make
           | adapters.
           | 
           | Maybe if I stared at it for twelve years it would become
           | familiar and I would begin to think it was simple, readable
           | and maintainable.
        
             | jghn wrote:
             | Yeah. Sure, "simple" and "complex" sorta have an objective
             | definition. But colloquially "readable", "simple",
             | "complicated", etc have a tendency to track with "things
             | with which I'm familiar/comfortable (or not)".
             | 
             | Over the decades I've come to the conclusion that there's
             | no such thing as a one size fits all sweet spot on this
             | stuff. Different people are going to have different
             | experiences with what they find straightforward or not.
             | They will have different backgrounds, mental models, ways
             | of perceiving the world. It all adds up. As a profession we
             | need to understand this reality and find ways around it
             | instead of getting into dogmatic arguments as if there's
             | One Right Answer.
             | 
             | Common example I give - the GP complained about FP
             | advocates wanting code to take up less screen space. I have
             | come across many devs who struggle with concise code, and
             | many others who struggle when code is _not_ concise.
             | Similarly, I have come across plenty of devs who start
             | having trouble when code is spread out (sometimes that
             | means within a file, across files, both, etc). I have also
             | come across plenty of devs who have trouble when it 's all
             | pulled together.
        
           | bigDinosaur wrote:
           | Pretty poor attitude to just adopt so generally. I've seen
           | 'actively harmful' qualities from all paradigms. Once peoples
           | start adopting attitudes like yours they've just become the
           | mirror of the condescending FP type and just kill outright
           | any of the really cool features that are useful, as well as
           | any discussion of them.
        
             | wokwokwok wrote:
             | Do whatever you want with your own code bases; my
             | responsibility is to make the ones I work on maintainable
             | by other people.
             | 
             | /shrug
        
               | cpursley wrote:
               | Some of us don't find OOP code maintainable.
        
               | wokwokwok wrote:
               | It doesn't matter if it's FP or OOP.
               | 
               | Here's the real question: do you think dense code is more
               | maintainable?
               | 
               | Generally yes? More than a verbose multilayered
               | abstraction, probably?
               | 
               | ...but where do you draw the line? Map statements instead
               | of for loops? Collapse all the white space onto a single
               | 200 character line? Make everything one big regex?
               | 
               | Dense code means that every change has more impact,
               | because there's _less code_ ; it's unavoidable: less code
               | to do the same work means more impact from changing any
               | part of that code.
               | 
               | That is why it's difficult to maintain; because you can't
               | touch it without making side effects; you can't reason
               | about a _small part_ of the code, because the logic is
               | dense and difficult to unpack into small parts.
               | 
               | Certainly OOP can often be verbose and _annoying_ , but
               | that's a different thing.
               | 
               | Code density and _being functional_ are orthogonal; some
               | OOP is too dense too. ...but _generally_ I've found that
               | inexperienced people see _density_ and strive for it,
               | believing this makes it functional; but the truth is the
               | opposite.
               | 
               | Good functional programming is often naturally _concise_
               | , but most people don't actually seem to understand FP.
               | 
               | They just seem think it means to put more "reduce"
               | statements in the code, remove for loops and generally
               | make the code harder to debug and denser.
               | 
               | ...in my, limited experience, working with lots and lot
               | of different folk at many different organisations.
        
               | cpursley wrote:
               | For me it's not density - it's the OOP class abstractions
               | and all that. I'm not smart enough to keep up with it vs
               | the FP approach of just doing data transformations.
        
               | CharlieDigital wrote:
               | I think of OOP done well at a high level as "structural
               | logic". Whereas in FP, one might use `map()` and `bind()`
               | to replace complex imperative logic flows, in OOP, this
               | is done with object hierarchies and structures.
               | 
               | When you have a abstract base class or an interface that
               | defines some contract, it's creating a "shape" that
               | defines how an instance of the class can be used.
               | 
               | I think that this might be why some folks have an
               | affinity for OOP and some have an affinity for FP. OOP
               | affinity might be tied to more visual thinkers. For me, I
               | see the "shapes" of the code defined by the contracts.
        
           | delta_p_delta_x wrote:
           | Perhaps the snark caused the down-votes, but your point is
           | legitimate. 'Pure FP' languages _encourage_ code that is
           | nearly unreadable and unparseable without any additional
           | context (and sometimes, unreadable even _with_ said context).
           | There is some strange desperation for extreme terseness in
           | pure FP languages like Haskell, Ocaml, Idris, etc.
           | 
           | Single-character variables and functions, point-free style...
           | Coming from an imperative background, this just seems like
           | flexing for the sake of flexing.
           | 
           | Why not make life a _little_ easier by clearly naming
           | variables? This isn 't maths or physics where variables (for
           | some equally-inane reason) _must_ be one character. We have
           | 4K screens today; I can accept lines that are significantly
           | longer than 80 chars.
        
             | BigJono wrote:
             | There's nothing wrong with single character variables if
             | you're not using them like a complete idiot. A line like
             | reports.map(r => whatever) makes it blatantly obvious that
             | r is a report.
        
             | toastal wrote:
             | When your code is sufficiently abstract, there often really
             | aren't better variable names than a or x. My experience is
             | that it's about the scope for that variable. If it's in a
             | one-line lambda, then it'll be one letter. If it is going
             | to be used in the next 10 lines or so, make an abbreviator.
             | And it's longer, or particular unclear, spell it all out.
             | Adding extra words don't make
             | BusinessAbstractFactoryIBuilder more readable.
        
               | delta_p_delta_x wrote:
               | > BusinessAbstractFactoryIBuilder
               | 
               | While I understand and agree with this meme[1], I think
               | that's the other extreme, where everything is a Factory
               | Builder thing.
               | 
               | Even so, I would rather too much information than too
               | little, which is what FP programs tend to do. Over-
               | abstraction is _also_ a problem, in my view. Even in a
               | LINQ lambda, for instance, I might write
               | someEnumerable.Select(what_is_actually_inside =>
               | doSomething(what_is_actually_inside))
               | 
               | rather than                 someEnumerable.Select(x =>
               | doSomething(x))
               | 
               | [1]: https://github.com/EnterpriseQualityCoding/FizzBuzzE
               | nterpris...
        
               | toastal wrote:
               | Funny example since currying requires no intermediate
               | variable to speak of                   someEnumerable |>
               | select doSomething
        
             | c-cube wrote:
             | Fwiw, OCaml doesn't chase extreme terseness or point-free
             | programming. It's not really equipped for that.
             | 
             | OCaml is designed for straightforward code centered on
             | functions, modules, and a mix of imperative and immutable
             | data structures; all with a _really_ simple execution model
             | and a pretty nice type system. The core language has very
             | few quirks and it's easy to predict what it does, and how
             | efficiently.
             | 
             | There's not really any comparison with Haskell, which
             | emphasizes heavy optimizations to make its terseness, based
             | on lazy evaluation, work well in practice.
        
           | sunwukung wrote:
           | I think this is about the level of abstraction. As React
           | component extraction is to tag soup, so named functions
           | composed are to fp primitives. In code reviews, if I see a
           | big swamp of pipe/fold/cond etc at the top level, I'd kick it
           | back and ask that to be wrapped in a named function that
           | explains what it does, rather than exposing it's guts.
           | 
           | Writing concise, clear code is a skill that straddles any
           | paradigm.
        
       | substation13 wrote:
       | Alice: I don't need functional programming, I am very productive
       | in my imperative / OOP language.
       | 
       | Bob: What about feature x?
       | 
       | Alice: Oh yeah, well we can add that! It has proven useful.
       | 
       | Bob: Agreed! But now do you see the need feature Y?
       | 
       | Alice: Hmm good point. Feature X would be better with Y. Let's
       | add that too.
       | 
       | (Repeat n times)
       | 
       | Alice: Isn't my language pretty nice now?
       | 
       | Bob: I have to agree, it's very productive
       | 
       | Alice: See I told you, we don't need an FP language after all!
       | 
       | Bob: ...
        
         | draw_down wrote:
        
       | gspencley wrote:
       | > To hear some people talk about functional programming, you'd
       | think they'd joined some kind of cult.
       | 
       | I know that the chapter and book is coming at the topic pro-
       | functional, and there's nothing wrong with that. But boy does
       | that sentence ever ring true as a web application developer.
       | 
       | Functional brings with it a set of core principles and values
       | that provide a lot of benefit. So does OOP. So does procedural.
       | I'm a fan of always picking the right tool for the job at hand.
       | 
       | And JavaScript certainly brings with it a set of Functional-style
       | features. Use them liberally, by all means. Let them solve
       | problems for you.
       | 
       | As a professional, learn as much as you can about Functional
       | programming. Also learn as much as you can about OOP, imperative
       | approaches, procedural and any topic that will be relevant to
       | your field. Be the best professional that you can possibly be.
       | 
       | But don't, for the love of God, try and write a modern frontend
       | web application written in JavaScript (or TypeScript) from a
       | "purely" Functional-first point of view. Not only will you fail
       | and hate your life, but you will throw out lots of babies out
       | with tons of bathwater.
       | 
       | JavaScript is not even close to a Functional language. It doesn't
       | matter if Brenden Eich wanted to bring Scheme to the browser,
       | that's not what he ended up creating. Not only is it far from
       | being a functional language, but I would argue that it is
       | downright antithetical to FP.
       | 
       | - Everything is mutable, even functions themselves.
       | 
       | - Not only does JS have a mutable global namespace but modern
       | frontend apps often have to deal with no fewer than FOUR shared
       | global states (the global namespace, state management a la redux
       | store, local storage and server-side persistence). If cookies
       | still count then that might count as five.
       | 
       | - Functional programming favours primitive types. Simplicity is
       | the name of the game. Most client/server applications have to
       | deal with rich domain models. Functional is great for
       | "processes", while OOP is great for "things" (i.e: rich domain
       | modelling and grouping data structures with the logic that
       | mutates them).
       | 
       | - The asynchronous event loop brings side effects as a core
       | feature of the language. Yes we have strategies for putting our
       | side effects in a corner, but the entire application is built
       | from the ground up around the concept of side effects. Instead of
       | taking simple input and producing simple outputs, we send things
       | off to the server and/or update a global state store so that
       | multiple things can update independently. Side effects are
       | integral to a complex web application, no matter how many pure
       | functions you write (and you should write pure functions whenever
       | you can, they are simple, easy to test and debug).
       | 
       | None of the above should matter except that I have come across
       | many FP "purists" who come at the topic from a borderline
       | religious angle.
       | 
       | I think this has to do with how trendy our industry is. OOP was
       | very hot in the 90s and 2000s. FP start to gain traction, at
       | least in web development, with the advent of Scala and Douglas
       | Crockford's JavaScript The Good Parts. There is a tendency in our
       | industry to think in binary terms. That we saw lots of problems
       | with OOP applications and FP is promising a solution therefore
       | OOP = evil and FP = a gift sent down form the heavens to save our
       | souls. Nothing could be further from the truth, and trendiness is
       | the root of all evil IMO.
        
       | z9znz wrote:
       | Following TFA example, I think there's one more step that could
       | be done (or could have been done earlier in the processes) -
       | shift from piped, hardcoded function calls to a data structure
       | which describes the transformations you would like to have
       | applied to your data.
       | 
       | With just a few lines of mini-framework definition code, you can
       | define a Processor system which behaves like a pipe+reducer but
       | takes a simple data structure of initial value, functions to call
       | with that data (and optional additional params), with the result
       | of each step fed to the next. But in the framework you take the
       | output of the previous step and update the results key within a
       | process hash. Or if the function fails, you can accumulate errors
       | in an errors key-value pair. Steps can have flags, such as :hard-
       | fail, etc. which the Processor can use to affect special
       | behaviors (like a rollback or a termination) based on errors in
       | steps.
       | 
       | This enables really dynamic programming options as the
       | transformations to be done on the data can be determined at
       | runtime based on formulas or process generators.
       | 
       | It might seem that such an approach would make debugging and
       | troubleshooting more difficult, but because you can add
       | additional metadata and debug behaviors to the Processor steps
       | data, tracing exactly what has occurred in very easy.
       | 
       | The only downside I've found from this approach is that IDEs may
       | not "see" your call to functions as they are just references or
       | strings/symbols (depending on the language).
        
       | Cort3z wrote:
       | As far as I can tell, with this async approach you lose what I
       | consider to be one of the main benefits of the native async
       | functions; If an error is thrown, it will show up in the "reject"
       | path of your promise. This is very useful and is great at
       | preventing "random code" in some Task from causing havoc.
       | 
       | I'm not that great at functional programming, and perhaps this is
       | a non-issue, but I feel there could be some way to achieve the
       | same results without losing that ability.
        
       | onetom wrote:
       | omg, so much negativity here...
       | 
       | you should read the previous articles from the author, eg.
       | https://jrsinclair.com/articles/2022/javascript-function-com...
       | 
       | then
       | 
       | https://jrsinclair.com/articles/2022/what-if-the-team-hates-...
       | 
       | it would address some of the concerns and critiques ppl had on
       | this topic here.
        
       | zactato wrote:
       | Obviously the best part of Functional Programming is arguing
       | about the pedantics of whether a language or construct is
       | actually "functional"
        
       | germandiago wrote:
       | I think functional programming is great for scaling systems but
       | too restrictive since everything is immutable...
       | 
       | So the model of the future, in my opinion, should look more like
       | https://www.val-lang.dev/
       | 
       | https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p26...
       | 
       | This is less restrictive and also very scalable IMHO. Value
       | semantics, basically.
        
         | mrkeen wrote:
         | > I think functional programming is great for scaling systems
         | but too restrictive since everything is immutable...
         | 
         | It's how things work at scale too.
         | 
         | Source control? Git
         | 
         | Money? Ledgers
         | 
         | Distributed computing? Map-reduce, Raft
        
           | germandiago wrote:
           | Lol. True. Concurrency without stopping...
        
       | FpUser wrote:
       | >"What's so great about functional programming anyway"
       | 
       | Well, nothing. It is one of many paradigms. It has its place just
       | as the others.
        
       | sbf501 wrote:
       | One downside is that you now have a much higher bar for hiring
       | talent to do trivial things. If you don't understand FP at a
       | fundemental level, you will have a hard time finding people to
       | work on your systems. Junior/Senior engineers are meant to be
       | fungible to an extent. This ups the bar to a new language: this
       | ain't JavaScript, it's an entire conceptual framework on top of
       | JavaScript.
        
       | revskill wrote:
       | Instead of
       | 
       | const x = await promise1(someArgs); const y = await
       | promise2(someFunction(x));
       | 
       | we do
       | 
       | function processor(monad, args) { return
       | monad.unit(promise1(args)).map(someFunction).then(promise2) }
       | 
       | That's all about monad.
        
       | dna_polymerase wrote:
       | Just a quick heads-up, if you want to truly write functional code
       | in the browser there is js_of_ocaml available in the OCaml realm.
       | With Bonsai [0] a somewhat usable framework for webapps is
       | available now, too. There are drawbacks like filesize, but if you
       | don't have to serve the webapp on the first pageload it shouldn't
       | be a problem.
       | 
       | [0]: https://bonsai.red
        
         | davidgl wrote:
         | Or https://fable.io in the F# world, which is production ready
         | and excellent
        
       | koonsolo wrote:
       | This post actually confirmed my opinion about functional
       | programming :D. Probably not in the way the author intended.
        
       | valtism wrote:
       | When talking about writing lodash V5, jdalton (the creator) said
       | "No FP wrappers. That fad is over. RIP your co-workers if you
       | introduced that headache into your codebase. Definitely not team
       | or human friendly." [1]
       | 
       | To me, this sort of FP seems to have been tried and have failed.
       | I don't know how much of this is due to the language and how much
       | is due to the pattern not working well in the minds of
       | developers. I wonder if JS had an implementation of something
       | like C#'s LINQ if it would be easier to write code this way.
       | 
       | [1] https://twitter.com/jdalton/status/1571863497969119238
        
         | neonate wrote:
         | What does FP wrappers mean in this context? Someone asked that
         | in the Twitter thread and got a snarky response, but I have the
         | same question.
        
           | rahkiin wrote:
           | I think they mean what in lodash was _() and .values(): You
           | could not execute map or filter on an array. Instead you
           | needed to wrap it in a lodash object using _(arr), that you
           | can call .filter() on. To get the filterd values out, you
           | call .values() on its result. You could also do _.filter(arr,
           | ...). To me it became confusing when I needed to use .values,
           | and when nesting it got worse.
           | 
           | LINQ has instead methods on its types that partially returns
           | builders. I find that easier to use, and using C# type system
           | it calculates the result types for me.
        
       | throwaway0asd wrote:
       | I am not a zealot as the book might describe. My personal goals
       | are portability and predictability of code. Use of functions with
       | defined return types in TypeScript, as opposed to other
       | containers by reference, allow me to achieve those goals.
       | 
       | Most of my functions though are void functions (returning null or
       | undefined). It's not essential to me that functions must return a
       | value, in defiance to functional programming, so long as like
       | instructions are grouped in a single container that may be called
       | by reference.
        
       | SPBS wrote:
       | `sanitizeMessage` is literally just `message.replace(/</g,
       | '&lt;')` but it has to go through a ton of abstractive
       | scaffolding just so that it can fit into a single call to map().
       | This is like jumping through a ton of generic classes in Java
       | only to find a single one-liner implementation at the end of the
       | call.
        
         | z9znz wrote:
         | I believe that his example for sanitizeMessage() was just to
         | give an example. An actual sanitizer would be much more
         | complex, and thus having a separate function defined to do that
         | one thing would be more obviously reasonable.
         | 
         | But you DO want these single responsibility methods like
         | sanitizeMessage()! Having single responsibility functions like
         | this means you have more Legos you can use where you need. You
         | get improved code reuse. Perhaps more importantly, you also get
         | functions which are easy to test and test more thoroughly than
         | if you have a big procedure which does a lot of things.
        
       | allenleein wrote:
       | For example, Haskell is optimized for developer efficiency. You
       | can get a lot done, have a high degree of confidence that it runs
       | reasonably without having to do too much thinking or ass-
       | covering. We move fast & need things to be reliable. Rather than
       | hand optimizing Doom 2 for ___.
        
       | toolslive wrote:
       | In the end, it boils down to the insight that functions compose
       | better then classes, interfaces and objects. Also, OO and
       | relational databases don't like each other. On the one hand you
       | have trees as basic weapon for composition while on the other
       | hand you have something where a tree is taboo.
        
       | dmitriid wrote:
       | Before you come at me with pitchforks: I built commercial
       | software with Erlang. I use functional(-style) programming in all
       | languages that support it.
       | 
       | I skimmed through this, and came across this gem:
       | 
       | > If there happens to be an error, we log it and move on. If we
       | needed more complex error handling, we might use other
       | structures.
       | 
       | Yes. Yes, we _always_ need more complex error handling. So, show
       | us the  "other structures". It may just turn out to be that the
       | regular chain of `.map` calls with a try/catch around it is
       | easier to understand and significantly more performant than any
       | convoluted pile of abstractions you've built.
       | 
       | And then you'll need to handle different errors differently. And
       | then you'll need to retry some stuff, but not other stuff etc.
       | 
       | > this is a sample chapter from my upcoming book: "A skeptic's
       | guide to functional programming with JavaScript."
       | 
       | The problem is: it does a poor job of convincing skeptics why
       | this is great, or even useful. _I_ use, or used to use,
       | functional programming, and _I_ am not convinced by this chapter.
        
         | wruza wrote:
         | _show us the "other structures"_
         | 
         | "Left as an exercise to the reader". Reminds me those well-
         | known tutorials with todo lists and other trivial nonsense,
         | because a fully-fledged example would seed doubt of selling
         | points instantly.
         | 
         | Sometimes I think that our area is one big IKEA store. You look
         | at nice pictures, buy into the crap, and still feel okay
         | because you've built most of it yourself. Not getting that this
         | built-yourself part makes you relate to it much more than the
         | initial advertisement or the practical value.
        
           | dmitriid wrote:
           | > "Left as an exercise to the reader".
           | 
           | Or "draw the rest of the owl" :)
        
       | zelphirkalt wrote:
       | One thing FP, learned with a suitable language at hand, teaches
       | is, how often we unnecessarily reach for classes, when simple
       | pure functions will do just fine and will be better testable,
       | easier to understand, more reusable, and more composable.
        
       | eurasiantiger wrote:
       | In my opinion, FP is one tool in the toolkit, and is best suited
       | for expressing math-oriented things such as set operations,
       | analytics pipelines, and other kinds of data transformations.
       | 
       | For any kind of I/O, though, FP is not even applicable in the
       | pure sense of a function, as disk/network access is inherently a
       | side effect. JS can of course mask much of this with its
       | Promises.
       | 
       | Any kind of business-oriented logic, especially handling of
       | different kinds of data entities, is still good to encapsulate in
       | classes in OOP fashion. Classes are a good impedance match for
       | entity types, as instances are to entities.
       | 
       | Sometimes, though, data transformations are still more clearly
       | expressed in imperative style. At the very least they're more
       | accessible to juniors, unlike the innards of declarative
       | transformation engines.
       | 
       | Imperative, declarative, object-oriented, functional -- these are
       | all tools for different jobs.
        
         | mrkeen wrote:
         | > For any kind of I/O, though, FP is not even applicable in the
         | pure sense of a function, as disk/network access is inherently
         | a side effect.
         | 
         | If you meant to do it, it's an _effect_ , not a _side-effect_.
        
           | eurasiantiger wrote:
           | That's not what is meant with side effect in this context.
        
         | valenterry wrote:
         | Pure FP is most useful for IO. Without IO, the concept of pure
         | FP doesn't make any sense.
        
           | eurasiantiger wrote:
           | That doesn't make sense. Any function doing I/O is not pure
           | by definition, and while using an IO monad can shift the
           | impureness a bit to make a function behave as if it was pure,
           | it is not pure and cannot ever be pure. Can you explain?
        
             | valenterry wrote:
             | Yeah - I think from your explanation I can only deduce that
             | you don't know the actual definition and concept of pure
             | functional programming. Note that the term "functional
             | programming" has been watered down over time and now pretty
             | much means "use .map and .filter instead of a loop" etc.
             | Historically the meaning was different though, see:
             | https://en.wikipedia.org/wiki/Purely_functional_programming
             | 
             | With pure functional programming you essentially treat IO-
             | effects as a first class concept and make them explicit in
             | your code. You never "execute" IO directly but compose
             | small "blueprints" for doing IO into bigger blueprints and
             | so on until you end up with one big blueprint which is your
             | application. You then pass it to the runtime ("main() {
             | ...; return bigBlueprint; }") and then it gets executed.
             | 
             | In other words, pure functional programming treats IO as
             | more important compared to "regular programming" and
             | without any IO there would be no need to even do so. But
             | without any IO, a program wouldn't have any meaning,
             | because you want _at least_ expose the result of a
             | computation to the outside world.
        
               | eurasiantiger wrote:
               | I do understand the concept of pureness in the
               | appropriate context. However, it appears that you do not.
               | 
               | This is a good example, since it ticks all the boxes:
               | there is imperative code run as a side effect of
               | executing the code output by the compiler based on
               | declarations in functional style, including those
               | _impure_ IO-using functions.
               | 
               | Slapping IO on your function is making it explicit that
               | it is impure.
        
       | alexmolas wrote:
       | > One of the people I showed this to had an interesting reaction.
       | Their response was something like: "Hey! I like functional
       | programming because I'm lazy and incompetent. It's about all the
       | things I don't have to think about."
       | 
       | I can perfectly imagine the most intelligent and smart people
       | I've ever meet saying this same thing.
        
         | googlryas wrote:
         | Maybe a key part of intelligence is merely knowing your own
         | limitations.
        
           | masklinn wrote:
           | Or offloading so you have more room for the useful stuff.
        
         | EnKopVand wrote:
         | There is a Danish scientist called Morten Munster who's done
         | research on behavioural science. He's written a book for
         | management that's gotten very popular in my country, and this
         | is how I became acquainted with it back when I did a stint in
         | management (which around here includes getting a MBA type
         | education in management).
         | 
         | Aaaaaaaanyway, in it he talks about two ways of how we function
         | as human beings, and I'm likely presenting this wrong, but one
         | is basically the best practice theoretical mode of being and
         | the other is how we operate at 17:00 on a Thursday after a week
         | where both our children have been sick, and the overlaying
         | message is that everything that isn't designed for the second
         | mode of being is likely going to fail. Now the way it's
         | presented in the research and the educational material, this
         | has nothing to do with programming. It's more along the lines
         | of companies needing to formulate missions and goals that
         | aren't corporate bullshit, because nobody understands corporate
         | bullshit when they are faced with an angry customer some late
         | Thursday afternoon.
         | 
         | After a few decades in SWE, however, I've become sort of a fan
         | of designing software for that 17:00 Thursday EnKopVand
         | mindset, and functional programming helps a lot in that regard
         | because it kills soooo many of the complexity pitfalls that you
         | really don't want to deal with when you're tired, lazy and
         | incompetent. Of course the other side of this is that I'm not
         | religious about functional programming either, I rarely write
         | classes these days, but if there is a good reason to write one,
         | I will.
        
           | jiggawatts wrote:
           | Some systems require eternal vigilance to not blow up in your
           | face, others shepherd people towards the pit of success.
        
             | jsrcout wrote:
             | So true. Same with languages IMO. Not naming any names :-)
        
           | gehen88 wrote:
           | Wow, I was really expecting this to be an argument against
           | FP, until it wasn't. I love the concept of designing for
           | Thursday 5pm though. My approach to achieve that is simply
           | different (it doesn't include FP).
        
           | danieldk wrote:
           | _After a few decades in SWE, however, I 've become sort of a
           | fan of designing software for that 17:00 Thursday EnKopVand
           | mindset, and functional programming helps a lot in that
           | regard because it kills soooo many of the complexity pitfalls
           | that you really don't want to deal with when you're tired,
           | lazy and incompetent._
           | 
           | It's so funny, because I thought your comment would lead to:
           | when it's 17:00 on a bad day, I'd rather debug some Go code
           | that is perhaps mundane but easy to follow than a chunk of
           | Haskell code of a colleague that drank too much category
           | theory kool-aid.
           | 
           | Which goes to show that what one wants to debug at 17:00 on a
           | bad day is very personal?
        
             | jolux wrote:
             | > Which goes to show that what one wants to debug at 17:00
             | on a bad day is very personal?
             | 
             | It really depends, it's possible to write mundane, simple
             | functional code (though I think more common in OCaml and
             | Erlang than Haskell) but much of the community is sort of
             | very excited about all this higher-order stuff that might
             | be great but is not quite as useful and obvious as the core
             | primitives of algebraic data types and pattern matching. I
             | imagine a lot of people probably felt similarly about the
             | Design Patterns craze with OOP: it's not that OOP isn't
             | useful, just that inheritance is maybe not what you want
             | most of the time and not everything needs to involve design
             | patterns.
             | 
             | I'd rather be debugging an OCaml program than a Go program
             | for sure.
        
               | danieldk wrote:
               | Right, but I think (a combination of) certain
               | abstractions invite abstractionitis. OCaml and Erlang
               | avoid that to some extend by being more restrained about
               | what they add to the type system. On the other hand,
               | these languages allow side-effects, removing the need to
               | rely on monads, monad transformers, monad transformer
               | stacks, etc.
               | 
               | I agree that algebraic data types and pattern matching
               | lead to better code. But even though they were introduced
               | (?) by ML, there is nothing holding imperative languages
               | from adopting them (see e.g. Rust).
        
             | EnKopVand wrote:
             | I mostly write Typescript these days, and being lazy, I'll
             | just quote wikipedia, but I'd much rather debug:
             | const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
             | .filter(n => n % 2 === 0)         .map(a => a * 10)
             | .reduce((a, b) => a + b);
             | 
             | than:                 const numList = [1, 2, 3, 4, 5, 6, 7,
             | 8, 9, 10];       let result = 0;       for (let i = 0; i <
             | numList.length; i++) {         if (numList[i] % 2 === 0) {
             | result += numList[i] * 10;         }       }
             | 
             | Maybe it doesn't make so much sense in this simple example,
             | probably even less so if you're not familiar with
             | Javascript, but it mostly comes down to the state of what
             | you're working on. In FP you know what you get, how it
             | looks while you're working with it and exactly what to
             | expect as the outcome, in OOP, well, you sort of don't.
             | Reading Wikipedia, though, maybe what I like is called
             | Functional Programming with Higher-order functions and not
             | just Functional Programming?
             | 
             | Like I said. I'm not extremely religious about it, and I do
             | think a lot of OOP design principles and code practices are
             | slowly heading toward a more FP way of thinking. In that
             | way I think it's sort of interesting that you mention Go,
             | because with Go you seem to mostly work with immutable
             | states and functions, rather than mutable objects, which is
             | more functional than imperative programming, but maybe I
             | just haven't worked enough with Go to know better. If you
             | ask me, everything should frankly be immutable by default,
             | but retrain the ability to become mutable like they do it
             | in Rust with the "mut" keyword. I really, really, enjoyed
             | working with that for the brief period I did. Anyway, I'm
             | not sure I'm ever going to get into religious FP, I may
             | very rarely use classes, but it's not like an abstract
             | class can't be healthy for your 17:00 afternoon self once
             | in a while.
             | 
             | But basically every best practice in regards to OOP that I
             | was taught at university back 20+ years ago, the stuff they
             | still teach today (I'm an external examiner a few times a
             | year), has proven to be sort of useless in the real world
             | for me. Maybe it works in more professional or competent
             | organisations but it sure hasn't worked well in any place
             | that I've ever worked, and yes, it does feel sort of dirty
             | to examine people in theories I disagree with, but it's
             | good money and a good way to keep up with both the CS world
             | and possible hires.
        
         | float4 wrote:
         | Can confirm. I took Advanced Functional Programming for my
         | master's. Of the ~15 people who took the class, the majority
         | scored <=65% or gave up, a few people got pretty good grades
         | because they were reasonably intelligent and willing to put in
         | the work (me), and then there were a few people who scored
         | >=95% because the high levels of abstraction genuinely made
         | things easier for them.
         | 
         | That was when I learned that for some people, a monad _really_
         | just is a monoid in the category of endofunctors.
        
         | gizmo wrote:
         | When people call themselves "lazy and incompetent" they're not
         | sincere. It's the equivalent of an obviously fit person saying
         | "oh I'm so fat".
         | 
         | It's just fake humility. The same people would get offended if
         | you _actually_ suggested they were lazy and incompetent.
        
           | mejutoco wrote:
           | In a programming context lazy does not need to be a bad
           | thing.
           | 
           | https://thethreevirtues.com/
           | 
           | Incompetence, I agree, sounds either self-deprecating or
           | fake.
        
             | mfru wrote:
             | incompetence is most likely just the impostor syndrome
             | speaking
        
           | [deleted]
        
           | rowanG077 wrote:
           | I don't think this is true. How fat you are can be pretty
           | objectively measured and it won't change in the short term.
           | 
           | Being lazy and incompetent however is always fluctuating.
           | There are days I'm lazy, there are days when I can work 12
           | hours and feel energized. There is also days where everything
           | in my mind aligns and all the problems melt away. There is
           | also days where I ram my head into the wall on some
           | relatively simple problem.
           | 
           | The point being is that programming is something that no
           | human can do without errors. So you want a language that
           | provides as much low overhead guard rails as possible to stop
           | yourself from shooting yourself in the foot. Even on the days
           | you're lazy and incompetent.
           | 
           | That's how I see the statement they make.
        
           | hutzlibu wrote:
           | "The same people would get offended if you actually suggested
           | they were lazy and incompetent. "
           | 
           | Maybe, because it is all relative.
           | 
           | I know my flaws and compared to my (often unrealistically)
           | high standards, I feel incompetent quite a lot. So I can say
           | the above and mean it.
           | 
           | But if I get criticized as incompetent by someone way below
           | my level, then yes, I might take offense and depending on the
           | mood, also hit back (or ignore it).
        
           | taneq wrote:
           | I think it's often Socratic laziness. Not fake, but "humans
           | are dumb and weak, let's make this easy for ourselves."
           | 
           | For most of my coding work I take it a step further than this
           | with the simple premise that the code you wrote
           | professionally _is not for you_. It's for whoever next has to
           | work on it, no matter their level of expertise. Sure, maybe
           | _you_ 'just know' that the equality operator comes between
           | bitwise-OR and logical-OR in precedence, but the code isn't
           | _for_ you so maybe just use the brackets anyway.
        
           | [deleted]
        
         | [deleted]
        
       | DavidSharff wrote:
       | While there are areas where my functional convictions have
       | greatly diminished, my mid career zeal had the tremendous benefit
       | of illuminating new architecture and data design principles.
       | 
       | Storing data as discreet changes and relying on pure function
       | selectors to calculate values is wonderful.
       | 
       | It's not always a viable approach at scale (at least not for my
       | ability in certain circumstances) but, when it is, testing is a
       | breeze and I love being able to debug forward/backward in time
       | with consistent results guaranteed.
        
       | waltbosz wrote:
       | I really dislike when programming books are overly terse with
       | their code examples. This is a problem I've struggled with since
       | I was a child learning to code.
       | 
       | When I'm learning a new concept, I need to be able to clearly see
       | the steps. Even if I do understand how to read and write in the
       | abbreviated coding style, the extra step of mentally decoding it
       | into it's more verbose form takes mental energy away from the
       | absorption of new knowledge.
       | 
       | Clearly, this book is written for an advanced audience, but at
       | the same time it's trying to teach an unfamiliar concept to that
       | advanced audience.
       | 
       | Does anyone else here share my sentiment?
       | 
       | It makes me think of this software I saw once that would take a
       | math-problem, and solve it for you, showing you the steps along
       | the way to the solution. I want something like that for this kind
       | of code.
        
         | aeonik wrote:
         | I completely agree with you.
         | 
         | This was the main thing slowing me down when I started to learn
         | Clojure last year.
         | 
         | I'm now learning Emacs and and Elisp and I find the
         | documentation even more difficult to comprehend somehow.
         | 
         | Two examples: Literate programming with org-babel: almost none
         | of the documentation that I can find shows "real" examples with
         | multiple header properties or variables being set for an org-
         | babel file. I don't know how to mix and match them. The docs
         | tend to show the most minimal example and I've been spinning my
         | wheels for days trying to figure out how to integrate into my
         | workflow.
         | 
         | Another elisp example: using auth-sources.el for handling
         | credentials. I'm trying to enhance a few major modes to add
         | support for storing server credentials, and none of the
         | examples show how to actually prompt a user for a username and
         | password to save it for later in the secure key store. I've
         | checked other projects, and people do it in different ways, and
         | they all seem needlessly complicated, with core auth logic
         | embedded directly in unrelated function calls.
         | 
         | Compare this:
         | https://www.gnu.org/software/emacs/manual/html_mono/auth.htm...
         | 
         | To this: https://pypi.org/project/keyring/
         | 
         | Edit: I'd like to add, I am loving Emacs and Clojure. I think
         | it's worth the slog, but there is room for improvement for
         | making a lot of these systems more approachable to the complete
         | newcomers.
        
         | photochemsyn wrote:
         | The code examples shown here are highly confusing, and would
         | benefit greatly from code comments. One of the most nonsensical
         | trends I've seen in programming is the notion that 'code should
         | explain itself' and if it's well-written, extensive comments
         | are unnecessary.
         | 
         | The best way to improve this post would be to append comments
         | to each discrete code section, explaining clearly what other
         | code sections it interacts with, what it's intended to do, and
         | any other notes needed to clarify the functionality.
        
       | EVa5I7bHFq9mnYK wrote:
       | I always thought the benefit of FP is thread safety, at the cost
       | of a lot of data copying.
        
       | alexmolas wrote:
       | (Off topic comment) With the font you're using to write code it's
       | sometimes difficult to read some of the characters. For instance,
       | I had some problems to read the `getKey` method, since the `K`
       | char is pretty blurred.
        
         | rob74 wrote:
         | It's supposed to look like an old typewriter with partly broken
         | types, but it looks like they overdid it on the "K"... plus no
         | typewriter I know of can write with light color on a dark
         | background, so that kind of breaks the illusion.
        
         | joshcrowder wrote:
         | I came to write the same thing. Fine for reading text, not
         | ideal for code
        
       | macawfish wrote:
       | What's great about it for me is helping me stay focused on one
       | thing at a time. Composing and writing pure functions is easier
       | for me to reason about as someone with an easily distracted mind.
        
       | gizmo wrote:
       | GOOD: having large chunks of code that runs (mostly) without
       | side-effects. As projects get bigger global state can trip you
       | up, so try to keep it in check. That's where the real value of
       | functional programming is.
       | 
       | BAD: copying data needlessly and turning trivial stuff into a
       | functional pipeline that is impossible to debug. You want your
       | code to read top to bottom like the problem you're trying to
       | solve, if at all possible. If your call stack looks like map,
       | fold, reduce you've introduced a ton of complexity, and why
       | exactly?
       | 
       | Every programmer should understand functional programming. Higher
       | order functions can be super useful. Immutable objects are
       | invaluable for preventing subtle bugs. But if you feel the need
       | to transform simple linear code into a map of higher order
       | functions because of some abstract benefits you're probably doing
       | stuff that's too easy for you and you should get your mental
       | challenge from solving a more difficult problem instead.
        
         | piokoch wrote:
         | 100% agree, the monstrosity that author proposes is really hard
         | to swallow. Simple made hard.
         | 
         | The idea to handle validation (we get HTML instead of expected
         | JSON) by passing some Nothing object down the flow is horrible,
         | if we expect JSON and get something unparsable, well, the best
         | strategy is to fail fast and let know client side that we have
         | a wrong data. Instead we show off with some fancy code
         | structure with zero value for the user of the software.
        
         | mejutoco wrote:
         | Agree, especially with having as much part of the code as pure
         | functions.
         | 
         | I think where functional programming really shines is in
         | combination with a good type system, that can enforce those
         | restrictions. In languages like js I find it not so useful
         | (even if using map, filter, etc.) because I have no guarantees
         | that there is a hack somewhere in the function that I did not
         | see.
         | 
         | When there are a lot of pure functions the cognitive load is
         | reduced so much I can use the "extra capacity" to focus on the
         | task.
        
           | gizmo wrote:
           | In Javascript Object.freeze() and Object.seal() are wonderful
           | to prevent accidental mutation.
        
             | mejutoco wrote:
             | I did not know that. Another one is const to declare simple
             | variables. There are some features, I agree. But how do I
             | declare that a function returns a specific type and have it
             | enforced? IMO, only by switching to Typescript or similar.
        
               | gizmo wrote:
               | VSCode can enforce return types with jsdoc annotations,
               | even when using plain javascript. VSCode uses typescript
               | internally for all type inference, so you get that for
               | free. Type inference works flawlessly 95% of the time,
               | even for iterators/generators/inheritance/containers.
        
         | chriswarbo wrote:
         | > simple linear code
         | 
         | If you're talking about a sequence of statements, I've rarely
         | come across such a thing.
         | 
         | Firstly, the mere _existence_ of statements in a language is an
         | incredible complication:
         | 
         | - It forks the grammar into two distinct sub-languages
         | (expressions and statements)
         | 
         | - Expressions compose with each other, and with statements; but
         | statements don't compose with expressions.
         | 
         | - It introduces a notion of (logical) time into the semantics
         | ('before' a statement is executed, and 'after' a statement is
         | executed)
         | 
         | - The times of each statement need to be coordinated. Chaining
         | one-after-another is easy (usually with ';'), but concurrency
         | gives an exponential explosion of possible interleavings.
         | 
         | - The computer often cannot help us spot mistakes, and
         | compilers have very little ability to optimise statements.
         | 
         | This is especially silly in Python, where many common tasks
         | require statements, which often requires rewrites (e.g. we
         | can't put statements in lambdas; hence we often need separate
         | function defs (which themselves are statements); pulling those
         | out may lose access to required lexically-scoped variables,
         | requiring even more plumbing and wrapping; urgh.)
         | 
         | Compare this to functional code, where there's only a single
         | language (expressions) where everything is composable; where
         | there is no control flow (only data dependencies); there is no
         | notion of time; mistakes are more obvious (e.g. 'no such
         | variable' errors at compile time); compilers have lots of scope
         | to optimise; and code is trivial to parallelise.
        
           | bazoom42 wrote:
           | Worth noting Haskell ended up reinventing the
           | statement/expression distincion in the do-notation. So
           | apparently the distinction do have value.
           | 
           | "Logical time" actually matters when you have side-effects.
           | Of course we can agree code without side effects is simpler
           | to reason about. Unfortunately you need side effects to do
           | anything useful.
        
             | chriswarbo wrote:
             | > "Logical time" actually matters when you have side-
             | effects
             | 
             | "Time" doesn't matter; causality/dependency is what
             | matters. That is modelled quite well by passing around
             | values. For example:                 let hostname =
             | lookup("hostname")           username = lookup("username")
             | password = lookup("password")           connection =
             | connect(hostname, username, password)        in
             | query(connection, "SELECT foo FROM myTable")
             | 
             | The 'query' call depends on the result of the 'connect'
             | call, so it must "happen afterwards". The 'connect' call
             | depends on the result of the three 'lookup' calls, so it
             | must "happen afterwards". The 'lookup' calls don't depend
             | on each other, so they're concurrent (note that concurrent
             | does not necessarily imply parallel).
             | 
             | This form of data dependency is no different than, say,
             | arithmetic: to calculate '3 x (2 + 4)', the multiplication
             | depends on the result of the addition, so it must "happen
             | afterwards". (The imperative equivalent would be 'push 2;
             | push 4; +; push 3; x;')
             | 
             | > Worth noting Haskell ended up reinventing the
             | statement/expression distincion in the do-notation
             | 
             | Yes, do-notation "desugars" into plugging return values
             | into arguments, like above. This gets a little tedious for
             | things like 'IO', where we pass around a unit/null value to
             | represent "the real world".
             | 
             | Still, a nice lesson from Haskell is that there's value in
             | making things opt-in; e.g. many languages have
             | Maybe/Option, but it's less useful in languages which allow
             | 'null' anywhere; many languages have IO/Effect/Task/etc.
             | but it's less useful in languages which allow I/O anywhere;
             | etc.
        
               | garethrowlands wrote:
               | The real world type is a bit of an implementation detail
               | in GHC. As a user, you shouldn't really have to deal with
               | it. IO could be implemented differently under the hood,
               | though real world works well in GHC.
        
               | dmitriid wrote:
               | But then the real world rudely intervenes because
               | connections are flaky, services are down, and you need to
               | add logging to weird and unexpected parts of your program
               | because a call on device A is resolved in a weird state
               | on device B, and the backend reports that everything's
               | a-okay.
        
               | tsimionescu wrote:
               | Still, you're showing the simple case of code without
               | (global) side-effects.
               | 
               | What if instead we said                 let connection =
               | connect(hostname, username, password)           _ =
               | query(connection, "INSERT INTO t1 VALUES ('abc')")
               | data = query(connection, "SELECT * FROM t1")         in
               | print data
               | 
               | What is the order of the two calls to `query` actually
               | matters, but how could the language know?
               | 
               | The order of execution of code is actually important
               | every time you have such a side effect, and languages
               | that don't strictly define it make this type of thing
               | very error prone.
        
               | chriswarbo wrote:
               | > What is the order of the two calls to `query` actually
               | matters, but how could the language know?
               | 
               | The language can't "know the order" of these calls, since
               | _they are not ordered_. No information is passed from one
               | call to the other, hence neither is in each other 's past
               | light cone.
               | 
               | If you want to impose some order, you can introduce a
               | data-dependency between the calls; e.g. returning _some_
               | sort of value from the  "INSERT" call, and incorporating
               | that into the "SELECT" call. Examples include:
               | 
               | - Some sort of 'response' from the database, e.g.
               | indicating success/failure
               | 
               | - GHC's implementation of IO as passing around a unit
               | value for the "RealWorld"
               | 
               | - Lamport clocks
               | 
               | - A hash of the previous state (git, block chains, etc.)
               | 
               | - The 'connection' value itself (most useful in
               | conjunction with linear types, or equivalent, to prevent
               | "stale" connections being re-used)
               | 
               | - Continuation-passing style (passing around the
               | continuation/stacktrace)
               | 
               | > languages that don't strictly define it make this type
               | of thing very error prone
               | 
               | On the contrary, attempting to define a total order on
               | such spatially-separated events is very error prone.
               | Attempting to impose such Newtonian assumptions on real-
               | world systems, from CPU cores to geographically
               | distributed systems, leads to all sorts of
               | inconsistencies and problems.
               | 
               | This is another example of opt-ins being better than
               | defaults. It's more useful and clear to have _no_
               | implicit order of calculations imposed by default, so
               | that everything is automatically concurrent /distributed.
               | If we want to impose some ordering, we can do so using
               | the above mechanisms.
               | 
               | Attempting to go the other way (trying to run serial
               | programs with concurrent semantics) is awkward and error-
               | prone. See: multithreading.
               | 
               | See also
               | https://en.wikipedia.org/wiki/Relativistic_programming
               | 
               | Note that you haven't specified the database semantics
               | either.
               | 
               | Perhaps the connection points to a 'snapshot' of the
               | contents, like in Datomic; in which case doing an
               | "INSERT" will not affect a "SELECT". In this case, a
               | "SELECT" will only see the results of an "INSERT" if we
               | query against an updated connection (i.e. if we introduce
               | a data dependency!).
               | 
               | Perhaps performing multiple queries against the same
               | connection causes the database history to branch into
               | "multiple worlds": each correct on its own, but mutually-
               | contradictory. That's how distributed systems tend to
               | work; with various concensus algorithms to try and merge
               | these different histories into some eventually-consistent
               | whole.
               | 
               | PS: There is a well-defined answer in this example; since
               | the "INSERT" query is dead code, it should never be
               | evaluated ;)
               | 
               | PPS: Even in the "normal" case of executing these queries
               | like statements, from top-to-bottom, against a "normal"
               | SQL database, the semantics are under-defined. For
               | example, if 'query' is asynchronous, the second query may
               | race against the first (e.g. taking a faster path to a
               | remote database and getting executed first). This can be
               | prevented by making 'query' synchronous; however, that's
               | just another way of saying we need a response from the
               | database (i.e. a data dependency!)
        
               | tsimionescu wrote:
               | In most programming languages, the order of the two
               | statements would be well defined, and neither would be
               | dead code.
               | 
               | Trying to make all statements implicitly concurrent
               | unless they have explicit dependencies is a terrible way
               | to complicate your life. That in some cases you can
               | optimize the code (or the CPU will do it for you) by
               | executing it in certain other orders where it is safe is
               | supposed to remain an invisible optimization.
               | 
               | It is obvious to everyone that distributed code, eventual
               | consistency, and other similar non-totally-ordered
               | examples are much harder to get right than procedural
               | code. Even simple print-based debugging/logging becomes
               | excessively complex if you get rid of the local total
               | ordering.
               | 
               | Even most network-based computing is done over TCP (or,
               | more recently, QUIC) exactly because of how enormously
               | useful having a total order is in practice (even if it's
               | just an illusion/abstraction).
               | 
               | > PS: There is a well-defined answer in this example;
               | since the "INSERT" query is dead code, it should never be
               | evaluated ;)
               | 
               | It's only dead code if you assume Haskell's bizarre lazy
               | execution model. In virtually every other language,
               | unless the compiler can prove that query() has no side
               | effects, the INSERT will be executed.
        
           | t43562 wrote:
           | It might be easier to explain things to oneself in terms of
           | time though - we are not necessarily functional in thinking.
           | e.g. I imagine trying to explain f(g(x)) versus g(f(x))
           | without using the word "first" or "then"
        
             | chriswarbo wrote:
             | That's data flow, which is fine: the dependency is
             | explicit, checked by the compiler, and maintained
             | regardless of where the code lives.
             | 
             | For example, if 'foo = g(x)' is defined in one module, and
             | another module does 'f(foo)', then the data flow is
             | preserved. If we try to force things to be the wrong way
             | round, we'll get compiler errors like 'No such variable
             | foo'.
             | 
             | Compare that to temporal ordering of statements; if one
             | module executes 'g(x)' and another executes 'f()', how do
             | we ensure the latter occurs after the former? How could the
             | compiler tell us if they're the wrong way around? Very
             | difficult.
        
             | naasking wrote:
             | > e.g. I imagine trying to explain f(g(x)) versus g(f(x))
             | without using the word "first" or "then"
             | 
             | Use "from" and "to", which talks about data dependencies
             | rather than temporal dependencies. Most people assume
             | dependency order implies temporal order, and then you
             | introduce them to lazy evaluation to decouple even that.
        
           | chronial wrote:
           | > pulling those out may lose access to required lexically-
           | scoped variables
           | 
           | The only situation for this that I can think of is inside a
           | list comprehension / generator expression. You are aware that
           | you can define functions at any scope in python?
        
             | chriswarbo wrote:
             | > You are aware that you can define functions at any scope
             | in python?                 >>> lambda myVar: (def foo():
             | return myVar + 1, foo)[-1]         File "<stdin>", line 1
             | lambda myVar: (def foo(): return myVar + 1, foo)[-1]
             | ^       SyntaxError: invalid syntax
        
               | chronial wrote:
               | I didn't mention lambdas because this is obviously
               | transitive                 def f(myVar):           def
               | foo():              return myVar + 1           return foo
        
               | chriswarbo wrote:
               | Here's some made up code:                 pruned = map(
               | # Remove all elems whose foo is less than the number of
               | elems         lambda elems: list(filter(           lambda
               | elem: elem.foo < len(elems),           elems         ))
               | )
               | 
               | Now let's say we want a running total of all the foos. We
               | can insert an expression to do this:
               | total_foos = [0]       pruned = map(         # Remove all
               | elems whose foo is less than the number of elems
               | lambda elems: list(filter(           lambda elem: (
               | # Add elem.foo to our total_foos accumulator
               | total_foos.append(total_foos.pop() + elem.foo),
               | elem.foo < len(elems)           )[-1],           elems
               | ))       )       total_foos = total_foos.pop()
               | 
               | This is rather awkward and "non-Pythonic"; ideally we
               | would use 'total_foos += elem.foo', but that can't exist
               | in a lambda. Hence:                 total_foos = 0
               | # Have to define this outside the map, since it's a
               | statement       def checkAndAccumulate(elems):
               | """This checkAndAccumulate function is just a wrapper,
               | for closing-over         the elems variable (since it's
               | not in-scope outside the map call).         Returns the
               | actual checking+accumulating function."""         def
               | checker(elem):           """The actual function we want
               | to filter with"""           total_foos += elem.foo
               | return elem.foo < len(elems)         return checker
               | pruned = map(         # Remove all elems whose foo is
               | less than the number of elems         lambda elems:
               | list(filter(           checkAndAccumulate(elems),
               | elems         ))       )
        
               | chronial wrote:
               | I can only quote OP on this:
               | 
               | > But if you feel the need to transform simple linear
               | code into a map of higher order functions because of some
               | abstract benefits you're probably doing stuff that's too
               | easy for you and you should get your mental challenge
               | from solving a more difficult problem instead.
               | 
               | This code is only complicated because you insist on
               | following some abstract ideal. The actual way to solve
               | this in python is:                 total_foos =
               | sum(elem.foo for elem in elems)       pruned = [e for e
               | in elems if e.foo < len(elems)]
               | 
               | Which is shorten than even your first code sample. If you
               | directly translate your last example into sensible
               | python, you get a nice example of some "simple linear
               | code":                 total_foos = 0       pruned = []
               | for elem in elems:           total_foos += elem.foo
               | if elem.foo < len(elems):
               | pruned.append(elem)
               | 
               | The existence of statements in python clearly stands in
               | the way of achieving ideals of pure functional
               | programming. But I think aiming for such ideals is the
               | exact opposite of the point OP was making.
        
         | brap wrote:
         | Some solutions are much easier to express in an imperative way.
         | 
         | You can still write pure functions and avoid state in
         | imperative code. Use consts, immutable objects, etc. You get
         | some of the benefits of functional programming while still
         | writing readable code.
        
         | WastingMyTime89 wrote:
         | > copying data needlessly and turning trivial stuff into a
         | functional pipeline that is impossible to debug. You want your
         | code to read top to bottom like the problem you're trying to
         | solve, if at all possible. If your call stack looks like map,
         | fold, reduce you've introduced a ton of complexity, and why
         | exactly?
         | 
         | Hard to follow code is mostly a consequence of point-free style
         | in Haskell which is an heresy to be avoided at all cost.
         | 
         | ML typically uses a piping operator to compose code instead and
         | that leads to top to bottom code which is extremely easy to
         | read.
         | 
         | There is zero difference then between a map and a loop. Loops
         | are not read top down anyway nor are function calls. It seems
         | to me you are just more used to these indirections than other
         | ones and are therefor blind to them. This leads to an argument
         | which I consider a straw man personally.
        
           | lixtra wrote:
           | I tried googling for an example[1] and had difficulty finding
           | a good one.
           | 
           | Do you have a link to a good one?
           | 
           | [1] https://elixirschool.com/en/lessons/basics/pipe_operator
        
             | dpwm wrote:
             | Here is an example in ocaml, where |> is the pipeline
             | operator:
             | 
             | https://cs3110.github.io/textbook/chapters/hop/pipelining.h
             | t...
        
           | Chris2048 wrote:
           | > Loops are not read top down anyway nor are function calls
           | 
           | But their scope can be limited.
        
           | christophilus wrote:
           | I'm reminded of the Kernighan quote / trope: "Everyone knows
           | that debugging is twice as hard as writing a program in the
           | first place. So, if you're as clever as you can be when you
           | write it, how will you ever debug it?"
           | 
           | This phenomenon seems to happen more frequently with FP or
           | related tools and languages (RxJs abstraction soup comes to
           | mind).
        
             | wiseowise wrote:
             | This sounds really cool, except it was written in 1978 and
             | has nothing to do with modern realities of functional
             | programming or tools.
             | 
             | > RxJs abstraction soup comes to mind
             | 
             | Merely a side effect of being implemented in a language
             | that wasn't really designed for it.
        
               | jimbokun wrote:
               | In my opinion it's just as true today as in 1978, if not
               | more so, but functional programming can make code simpler
               | to reason about and therefor debug.
        
         | [deleted]
        
         | samsquire wrote:
         | I would rather inherit someone's stateful JavaScript or Java
         | than a complicated codebase by a seasoned Clojure, Haskell,
         | Scala developer.
         | 
         | I stand a better chance understanding the sequential code than
         | a complicated recursive (edit: nested) monad. Depending how it
         | was written.
         | 
         | I can probably understand Kafka pipeline's or a functional map,
         | reduce pipeline.
         | 
         | My parser for my programming language which I'm building is a
         | recursive Pratt parser but it's written in Java.
         | 
         | I want to understand functional programming better. I am
         | interested in software transactional memory and parallelism. I
         | am aware Erlang and Go use message passing but only Erlang is
         | functional.
         | 
         | In theory functional code can be parallelised due to
         | immutability but you need some kind of communication to
         | indicate transference of values. Imagine a pipeline where you
         | need to share a value to a few other threads. I'm aware Haskell
         | has software transactional memory
        
           | epgui wrote:
           | Is there even such a thing as a "recursive monad"? That
           | sounds made up.
        
             | WastingMyTime89 wrote:
             | No there is no such thing as a recursive monad. A monad is
             | a _type_ for which strictly defined operations are
             | provided. It can't be recursive by definition.
        
               | wiseowise wrote:
               | But hey, any strawman in the storm to make FP look bad.
        
               | [deleted]
        
           | throw827474737 wrote:
           | Also all "functional" programs have their state somewhere..
           | just usually much stricter isolated and manipulated - so no
           | difference in statefulness.
           | 
           | > I would rather inherit someone's stateful JavaScript or
           | Java than a complicated codebase by a seasoned Clojure,
           | Haskell, Scala developer. I stand a better chance
           | understanding the sequential code than a complicated
           | recursive monad. Depending how it was written.
           | 
           | True, but you add here the "complicated" attribute
           | deliberately .. usually it is the other way round. The
           | functional approach code is simpler to read and reason ( and
           | usually not with much recursive monoids), while the believed
           | sequential program has so many "concurrent" paths (even if
           | there is no real concurrency, but just in the many hidden
           | ways how the super distributed statefulness is manipulated)..
           | not?
        
           | amelius wrote:
           | > I would rather inherit someone's stateful JavaScript or
           | Java than a complicated codebase by a seasoned Clojure,
           | Haskell, Scala developer.
           | 
           | Isn't that simply because you're a Java developer (as I
           | understand from the rest of your post)?
        
           | Philip-J-Fry wrote:
           | Functional programmers are just as likely to make overly
           | complicated code the same as a developer in a conventional
           | language.
           | 
           | I'd rather inherit a complicated Java program than a
           | complicated Scala program. But I'd take a well written Scala
           | program over a well written Java program any day of the week.
        
           | lmarcos wrote:
           | Agree. The first version of the example (the one using only
           | `map`) is way easier to understand and maintain than the
           | rigmarole the author ended up with (writing their own
           | functors, pipes, peakerror and what not). It's like the
           | author didn't find the first version "complex" enough, so
           | they had to make it more complicated for the sake of
           | "functional programming".
        
         | galaxyLogic wrote:
         | Part of the problem with "functional pipelines" as in the
         | article is that you are in essence creating a domain-specific
         | language to describe the problem your program is modeling and
         | solving.
         | 
         | Problem is that is not a programming language supported by
         | anybody else than you. It is not part of the standard library.
         | If it was it would probably be of high quality, highly tested-
         | in-practice code.
         | 
         | But if you constructed your pipeline-framework (as in the
         | article) by yourself you now need to understand not only the
         | solution in terms of your created framework, but also how the
         | framework itself exactly works. If this is a one-off problem-
         | solution what looks like simpler code in the end hides its
         | complexity inside its framework-code. And as you keep
         | programming your framework is a moving target. You will improve
         | it from time to time. Understanding it becomes a moving target
         | too. It is a real problem for maintenance for you or anybody
         | else who wants to use and adapt your existing code in the
         | future.
         | 
         | Think about having the problem and a solution and being able to
         | describe both in English. But then you say hey if I invent this
         | new language Klingon and express the problem and solution in
         | Klingon, then both the problem and solution become simpler.
         | Cool. But now you must also program the Klingon interpreter for
         | yourself. And be aware of which version of Klingon your code is
         | assuming is used.
         | 
         | This is the tendency and cost of over-engineering. It is fun
         | and natural to look for the "ideal solution", but it comes with
         | a cost.
        
         | Gordonjcp wrote:
         | I don't get the point of "immutable objects". Why have an
         | object at all? Why not just hardcode the values if you want
         | them not to change?
        
           | spc476 wrote:
           | It's about trusting a function call. Imagine the following C
           | functions:                   extern result fubar(struct foo
           | *);         extern result snafu(struct foo const *);
           | 
           | Just by looking at the function prototype, I know that
           | calling snafu() won't change the struct foo I pass it. I
           | don't know what fubar() will do to it. Maybe it won't change,
           | maybe it will. I'd have to check the implementation of
           | fubar() to find out.
        
           | jimbokun wrote:
           | The idea is that a given object never changes, but it's
           | straightforward and efficient to create a new object from the
           | original one with some of the values changed.
           | 
           | This is "safer" for any code still operating on the original
           | object, as it will not be changed unexpectedly.
        
           | i_no_can_eat wrote:
           | immutable means that you set them only once, typically at
           | runtime. _Not_ that they have the same values always,
           | everytime you run.
        
           | [deleted]
        
           | dopidopHN wrote:
           | Those are often records from a database. There is a way to
           | change it, it's to make a copy of it.
           | 
           | I like being able to trust that something is what I think it
           | is because it cannot be something else. Meaning: if I know
           | that something can't change, I don't have to check for
           | eventual accidental change.
        
             | Gordonjcp wrote:
             | But now you've got two versions of it that aren't the same.
             | Why is that supposed to be good?
        
               | naasking wrote:
               | Because of aliasing. Some other functions/objects/threads
               | may have a reference to the old version. If they were in
               | the middle of a computation using that object, they don't
               | have to add a whole bunch of checks to ensure that the
               | data they're holding didn't suddenly change from
               | underneath them. This happens a lot in concurrent
               | programming, but even in single-threaded programs it
               | makes reasoning about the current state of the system
               | easier.
        
           | andrekandre wrote:
           | "immutable" is kind of overloaded term, but what it means in
           | this context is an object itself doesn't mutate when you want
           | to change a value (basically value semantics[0] instead of
           | reference semantics[1])
           | 
           | for example (pseudocode)                 var newUser =
           | Person(name: "some guy", age: 0)            // newUser is
           | replaced with a new object that is       // initialized with
           | field.name and previous age (0)       // the old object is
           | discarded       newUser.name = field.name            //
           | object is passed as copy-on-write, assuming a 1 sec delay
           | // it will print the objects values at this point in time
           | // (age: 0) even if altered later       async(after:1) {
           | print(newUser.age) } // prints 0            // age was
           | changed to 32 a nanosecond later,       // but now a new
           | object again is initialized       // instead of mutated
           | newUser.age = 32        print(newUser.age) // prints 32
           | ----------       output:         32         0
           | 
           | [0] https://en.wikipedia.org/wiki/Value_semantics
           | 
           | [1] https://stackoverflow.com/questions/27084007/what-is-
           | value-a...
        
           | TeMPOraL wrote:
           | The point is that if you have a reference to such object, you
           | know for sure it'll stay looking the same way at all times,
           | no matter what happens in the program. E.g. take this
           | pseudocode:                 let foo = MakeMeAnObject();
           | let bar = MakeSomethingElse(foo);
           | DoSomethingForSideEffects(foo, JoinThings(bar, baz));
           | return foo;
           | 
           | With immutable objects, you can be certain that neither foo
           | nor bar were modified by any of this code. So, when e.g.
           | debugging a problem with that DoSomethingForSideEffects()
           | call, you don't have to worry about values of foo and bar
           | having been changed somewhere, by someone, between their
           | introduction and the point you're debugging.
           | 
           | Neither of them _can_ be modified by it in the future - e.g.
           | someone else can 't change MakeSomethingElse() to also modify
           | its inputs, thereby accidentally breaking your code that's
           | using this function.
           | 
           | Another way of looking at it: a lot of problems with
           | reasoning about code, or parallelism, can be drastically
           | simplified by assuming the data being passed around is only
           | copied, and not modified in-place. "Immutable objects" as a
           | language feature is just making this assumption the default,
           | and enforcing it at the language/compiler level.
           | 
           | In terms of use, it isn't that much more inconvenient over
           | mutable objects. You can always do something like:
           | foo = DoSomeTransformation(foo);
           | 
           | It's just that DoSomeTransformation() is not _modifying_ the
           | object, but instead returning a new instance of the same
           | objects, with relevant fields having different values. The
           | obvious drawback here is, for large data structures, there
           | will be lot of copying involved - but that 's where the
           | languages with immutable objects are usually "cheating", e.g.
           | by using sophisticated data structures masquerading as simple
           | ones, as to only ever copy things that have actually changed
           | (i.e. "distinct" objects end up sharing a lot of their data
           | under the hood).
        
             | Gordonjcp wrote:
             | > It's just that DoSomeTransformation() is not modifying
             | the object, but instead returning a new instance of the
             | same objects, with relevant fields having different values
             | 
             | I can't think of anything where I'd want that. Don't you
             | end up needing infinite amounts of memory? Isn't it
             | absolutely slow as balls copying all that stuff around?
        
               | bongobingo1 wrote:
               | Not really. You can copy the new parts and reference the
               | old, garbage collect dead things, etc. At least in
               | languages where immutability is a core tenet vs stuck on
               | as an after thought.
               | 
               | Is it as fast mutable everything? No, _some_ copy must
               | happen, but is a mutable-standard languages as fast as
               | raw hand tuned asm? Also (probably) no, but the trade
               | offs are worth it. It likely matters a lot less than you
               | think unless you 're writing _actually_ performance
               | critical tight loop code vs just thinking about
               | performance.
        
               | dmitriid wrote:
               | If immutability is a part of the language, then the
               | compiler and the runtime know about it.
               | 
               | This way:
               | 
               | - passing an object around can always be by reference,
               | since no one can change it
               | 
               | - depending on structures used, for changed bits you
               | don't need to copy the entire structure, but simply shift
               | pointers to old data or new data
               | 
               | - garbage collection can become trivial, and granular,
               | since you know exactly what's new and old, and shifting
               | data around becomes just moving pointers around (again,
               | depends on implementation and optimisations)
               | 
               | There _are_ downsides if you are not careful, of course:
               | 
               | - creating a bunch of new data that references old data
               | _will_ run out of memory, but this doesn 't happen as
               | often as you would think.
               | 
               | - sending data between processes/threads _may_ result in
               | copying that data (depends on implementation)
               | 
               | However, the upside is quite good: your data never
               | changes under you. That is a call to func(data) doesn't
               | sneakily change data. _And_ all data becomes trivially
               | thread-safe without mutexes or race conditions.
        
           | idontpost wrote:
        
           | ankurdhama wrote:
           | It makes code easy to understand as you can easily identify
           | what is input and what is output and can easily figure out
           | the flow of data i.e what is being computed based on what.
           | Without immutable objects a function taking object can mutate
           | those objects and now they are acting as input and output,
           | which leads to complexity.
        
         | blauditore wrote:
         | Avoiding side-effects is usually lumped toghether with async-
         | style interfaces into the term "functional programming".
         | However, the two are separate properties with separate benefits
         | and downsides:
         | 
         | - No side-effects makes reasoning about logic easier, code more
         | deterministic, and tests more reliable. However, certain
         | problems become harder to solve (e.g. simple caching or
         | memoization).
         | 
         | - Async-style interfaces allow for waiting on slow operations
         | in a non-blocking fashion, meaning those don't occupy threads,
         | thus a more economic use of resources. However, async-style
         | code can be harder to read, write, and debug, though this
         | varies heavily between languages and frameworks.
        
         | kalekold wrote:
         | I've just left a startup company who's entire backend was
         | written in a functional style using Typescript by an agency.
         | The only reason I can fathom why is 'why not, functional
         | programming is cool right!'. A new dev team was created to take
         | over and it was a disaster. It was an absolute mess of piped,
         | mapped, reduced functions everywhere and completely unreadable
         | and unmaintainable. I remember getting lost in a hierarchy of
         | about 30+ piped (non db framework) functions to write a JS
         | object to a database. I didn't stay long.
         | 
         | Since I quit, the entire new engineering team quit and it looks
         | like the company is going under. Functional programming is a
         | big mistake for some real-world code.
        
           | atraac wrote:
           | > Functional programming is a big mistake for some real-world
           | code.
           | 
           | Generalizing much? I write C# for a living, Elixir in my free
           | time, I would take Elixir codebase any day of the week. If
           | you try to write C# in a strictly functional fashion it's
           | going to be shitshow as well. Moderation is the key, using
           | immutable data structures, getting rid of side effects if
           | possible etc.
           | 
           | You had a bad experience because you and/or people you worked
           | with simply tried to fit a square peg into a round hole, you
           | didn't get it in, threw a tantrum and now you're blaming all
           | the squares for being bad.
           | 
           | I on the other hand, after learning functional language, have
           | trouble looking at most code written by pure 'OOP
           | developers', most of it is a spaghetti shitshow of hierarchy
           | classes, dependencies and jumping across 20 different files
           | of factories and providers because DUHH sOlId and ClEaN. That
           | doesn't mean that OOP is a 'mistake for real-world code'.
        
           | eckza wrote:
           | Inexperienced developers that don't understand what they're
           | doing, armed with a language known best for being worst-in-
           | class at everything except for "running everywhere", is a
           | recipe for disaster, no matter how you spin it.
           | 
           | It feels egregious to implicate "the entire surface area of
           | functional programming" here, when there are other obvious
           | issues at play.
        
           | lolinder wrote:
           | > I've just left a startup company who's entire backend was
           | written ... by an agency. ... A new dev team was created to
           | take over and it was a disaster.
           | 
           | I honestly think these are the important bits of this story.
           | The startup outsourced their backend to an agency, _then_
           | tried to replace the agency with a brand new internal dev
           | team.
           | 
           | There's no way that story ends well, regardless of the
           | paradigm the agency chose or how skilled they might have been
           | (probably not very). _Every_ codebase is unmaintainable when
           | the team that built it is suddenly replaced.
           | 
           | Peter Naur had a lot to say about this in Programming as
           | Theory Building [0]:
           | 
           | > The extended life of a program according to these notions
           | depends on the taking over by new generations of programmers
           | of the theory of the program. For a new programmer to come to
           | possess an existing theory of a program it is insufficient
           | that he or she has the opportunity to become familiar with
           | the program text and other documentation. What is required is
           | that the new programmer has the opportunity to work in close
           | contact with the programmers who already possess the theory,
           | so as to be able to become familiar with the place of the
           | program in the wider context of the relevant real world
           | situations and so as to acquire the knowledge of how the
           | program works and how unusual program reactions and program
           | modifications are handled within the program theory.
           | 
           | [0] https://gist.github.com/onlurking/fc5c81d18cfce9ff81bc968
           | a7f...
        
           | mhitza wrote:
           | > Functional programming is a big mistake for some real-world
           | code.
           | 
           | The emphasis on "some" should be stronger in your comment,
           | otherwise it reads, on a quick pass, as a broad dismissal of
           | functional programming.
           | 
           | Functional programming concepts and ideas have been steadily
           | incorporated in most mainstream languages in the last 10+
           | years. However, when people move past the language's
           | functional programming primitives, it's when the project
           | enters potentially dangerous territory. Your, and the
           | article's, example of pipes, for one.
           | 
           | Personally, I'd like more languages to incorporate ADTs
           | (algebraic datatypes) for me to be able to "de"layer programs
           | back to a mostly procedural + functional programming. And
           | based on the current adoption rate of FP concepts, I'm not
           | sure we're that far away from having proper ADTs and pattern
           | matching in the most popular imperative programming languages
           | of today.
        
           | bigDinosaur wrote:
           | You can make code in any paradigm suck. You can do horrible
           | unmaintainable things in any language in any paradigm: Java
           | with twenty layers of abstractions, Python with immense
           | amounts of spaghetti, C with its hard to control safety. You
           | can also do awful, abysmal imperative or OOP code in
           | Typescript. So I just don't really see how you can single out
           | FP here at all. Your codebase sucked, and whoever was hired
           | to write it in a FP style just sucked at doing so. Sorry.
        
             | WA wrote:
             | > So I just don't really see how you can single out FP here
             | at all.
             | 
             | Not OP but imho, it's because FP is "sold" as the perfect
             | solution for readability and code maintainability. Just use
             | FP and nothing can go wrong. That's at least the impression
             | I get when I read about FP.
             | 
             | The fact that one can write abysmal OOP code is nothing
             | new.
        
               | wiseowise wrote:
               | > it's because FP is "sold" as the perfect solution for
               | readability and code maintainability. Just use FP and
               | nothing can go wrong. That's at least the impression I
               | get when I read about FP.
               | 
               | That's because it is. FP is not immune to incorrect
               | implementation. Both statements are true.
        
               | biorach wrote:
               | > Just use FP and nothing can go wrong. That's at least
               | the impression I get when I read about FP.
               | 
               | To be fair that was the kind of nonsense that was being
               | talked about OOP in the late 90's and early 2000's.
               | 
               | There are no silver bullets, and anyone who claims
               | otherwise is flat wrong.
               | 
               | However most techniques have their advantages, when used
               | well - and I'd say FP has more to offer than OOP in this
               | context.
        
             | Sohcahtoa82 wrote:
             | > Java with twenty layers of abstractions
             | 
             | Only twenty? That'd be a reduction.
             | 
             | If your stack trace doesn't have at least 30 calls of
             | "thingHandler.invoke()", you're not abstract enough.
        
         | wiseowise wrote:
         | Map, reduce and fold are much easier to reason about than
         | imperative loops, what's your problem exactly?
        
       | nonrandomstring wrote:
       | > (great? (programming(functional)))                 (allows
       | (ideas (elegantly(expressed))))
        
         | ludston wrote:
         | (-> except appropriate use of macros makes it easier to both
         | write and read)
        
       | ouid wrote:
       | functional programming has the same use to a programmer as
       | category theory does to a mathematician.
       | 
       | It is very good at describing the kind of objects we tend to care
       | about, so it is sensible to consider the converse and ask what
       | kinds of things is it good at describing.
       | 
       | how naturally we can express our code is a very strong measure of
       | how well we understand it. Both in terms of what it can and cant
       | do.
       | 
       | Imagine having blocks that stick together like legos, but you
       | cant see the dot lattice because your vision is too poor. FP is
       | about seeing the dots.
        
       | StreamBright wrote:
       | Using JS to try to prove or disprove anything is pointless. I
       | think a much better comparison is C# / F# for the exact same
       | problem. I think Scott Wlaschin's Railway oriented programming is
       | a prime example of a great OOP vs functional programming content.
        
         | jve wrote:
         | > I think a much better comparison is C# / F# for the exact
         | same problem
         | 
         | As a current reader of fsharpforfunandprofit.com, I'd like to
         | see modern C# comparison with F#. C# has introduced decent
         | pattern matching, records, nullables. LINQ was introduced long
         | time ago - many things that make F# possible. Here is some
         | comparison, but its 10 years old without the goodies C# offers
         | today: https://fsharpforfunandprofit.com/posts/designing-for-
         | correc...
        
       | piyush_soni wrote:
       | Yeah. I'm one of those who are not convinced yet about functional
       | programming being _so great_. In most cases what people call
       | functional programming are inefficient shortcuts to lengthier
       | functions, so I never got all that hype about it :\
        
         | spoiler wrote:
         | The nice thing about functional programming is that it allows
         | you to shift some of the "mundane" domain thinking onto the
         | type system. A classical example of that might be to mix units
         | in physics code. So, nonsenses like adding up lengths and time
         | is no longer possible.
         | 
         | Things also generally compose together more easily than in OO.
         | There's other benefits too, but these are my main ones.
         | 
         | So, once you set up this invariant groundwork, you free your
         | mind from thinking about certain problems, as the compiler
         | catches them for you.
         | 
         | This isn't to say these things can't be done in OO (they have
         | been done), but they're usually not enforced to the same level,
         | as it's normally a library, not native functionality
        
           | tsimionescu wrote:
           | The benefits of type systems are either entirely orthogonal
           | or at best are themselves a prerequisite for the benefits of
           | FP. Your example of measurement units in particular is
           | applicable to the most imperative goto laden code we could
           | think of.
           | 
           | In fact, some of the more popular functional languages are
           | untyped - those being Clojure, Erlang and Scheme.
        
             | piyush_soni wrote:
             | Exactly my point, I'm sure there are benefits, but this
             | example is more suited to Typed languages whereas many
             | functional languages like you say are untyped. And man,
             | I've worked with MIT Scheme in a major commercial software
             | for 5+ years. What a nightmare it was. :(. I mostly
             | understood the functional aspect of the language, but the
             | sea of misplaced brackets and a complete lack of any
             | debugger (at least for our version of it) whatsoever made
             | it one of the worst languages to work with. _The biggest
             | irony was, since Scheme is apparently so extensible, they
             | had created a home-grown "Object Oriented Scheme"_, which
             | implemented only _some_ aspects of OOP and omitted some
             | other very important ones, and it was upto the developer to
             | find out the hard way which ones were omitted! :D
        
       | booleandilemma wrote:
       | The other day I watched a self-described functional programmer
       | implement a while loop using this custom-written conditionally
       | recursive function.
       | 
       | There was nothing more elegant about it and it wasn't obvious
       | from just looking at the function call what the function was
       | doing. It wasn't any simpler than while(condition){}.
       | 
       | All because he didn't like while loops (and statements in
       | general). It seemed tortuous and unnatural.
       | 
       | FP has some good parts but so does imperative programming, and I
       | think throwing away the good parts of imperative programming and
       | OOP for the sake of "pure" FP is a serious mistake.
        
       | larsonnn wrote:
       | JavaScript is a bad example. We rely on so many libraries which
       | are not functional. React one of the biggest is not functional at
       | all.
       | 
       | Also JavaScript biggest advantage is that you can mix up. And
       | it's biggest disadvantage is that non experience developers will
       | mix up too.
       | 
       | Also you need to cloning multi level objects.
       | 
       | To work 100% FP in JavaScript you need the libraries and you need
       | to have a flat data structure every where.
       | 
       | I don't know how many JSON APIs you see who work like that.
       | 
       | JavaScript has also a rich set of language features you can use
       | to save your time and still have quality code.
        
         | weatherlight wrote:
         | I'm a huge fan of writing code in an FP style in a language
         | where that's the convention.
         | 
         | Erlang, Elixir, OCaml, Clojure, (Hell, even Ruby.)
         | 
         | The problem with the current state of JS and Its popular
         | libraries, is that the convention is to write OOP and
         | Imperative code. Unless your entire team is onboard, its causes
         | a lot of issues.
         | 
         | I feel like js-transpiled languages like Purescript, Rescript,
         | ClojureScript, ReasonML, etc do a really good job of allowing
         | Devs to write functional code on the frontend, while leveraging
         | the JS-lib ecosystem.
         | 
         | I personally have a hard time reasoning about while and for
         | loops, etc, and mutable variables, my monkey brain can't keep
         | track of that many spinning plates.
        
       | kriro wrote:
       | I basically write code in any paradigm but (loosely defined) FP
       | feels very natural to me. Immutable data and thinking about how
       | functions get some input and provide some output is the most
       | natural way of thinking about a domain for me.
       | 
       | I have no good way of describing what I mean but I tend to think
       | about functionality not things/items first I guess.
        
       | petilon wrote:
       | Worth noting: the author of this articles does not believe React
       | is functional:
       | https://twitter.com/jrsinclair/status/1398780972506619907
        
         | horsawlarway wrote:
         | To be fair - I mostly agree with that take. React with hooks is
         | _not_ functional. I think it 's fair to say that React itself
         | acknowledges this by making a distinction between a
         | PureComponent and a Component.
         | 
         | React itself certainly can be functional, but... (hot take)
         | functional programming without the part where you actually make
         | state changes is - drumroll - useless.
         | 
         | If it ain't changing state and there are no side effects - no
         | one gives a fuck. Because it literally isn't doing anything.
         | 
         | Turns out computers are fundamentally state machines.
         | Functional programming certainly has some nifty ideas, and it
         | can be a helpful way to reason about code that will lead to
         | state changes - but the part people want is the state change.
        
       | superasn wrote:
       | Just watched a video(1) about functional programming and this is
       | the gist of it (for those like me who don't know).
       | 
       | Three main things of functional programming:
       | 
       | 1. Keep your data and function independent
       | 
       | 2. avoid changing state of variables, instead declare others
       | 
       | 3. accept function/reference as a param
       | 
       | (1) https://m.youtube.com/watch?v=dAPL7MQGjyM&t=3s
        
       | Jorengarenar wrote:
       | Unfortunately, it didn't help to convince me either.
       | 
       | For me the question still remains: how is any of this better than
       | good ol' reliable `for` loop?
        
         | em500 wrote:
         | John Carmack on Twitter: "My younger son said "coding is
         | basically just ifs and for loops."
         | 
         | Which inspired this great cartoon:
         | https://twitter.com/nice_byte/status/1466940940229046273
        
         | mrkeen wrote:
         | How is the for-loop any better than good ol' GOTO?
        
           | wruza wrote:
           | In numbered-lines code you can't see the start of a goto
           | loop. In labeled-lines code it's not that hard to infer that
           | it is a jump target, but having a condition/iterator in one
           | place is an obvious benefit.
           | 
           | That said, I believe most people who "boo GOTO" never
           | actually used it to make sense of what could be wrong with it
           | and how it feels really.
           | 
           | Anyway, I think that this analogy(?) is confusing and makes
           | no sense.
        
           | koonsolo wrote:
           | Indeed! I started programming in GW-BASIC when I was 13. IF
           | and GOTO was all I needed! FOR, FUNCTION, ... why was it
           | there?
        
           | Jorengarenar wrote:
           | Conceptually, `for` loop is just syntactic sugar - it
           | simplifies certain action, not makes it more difficult.
        
             | pedrovhb wrote:
             | Conceptually, the `map` function is just syntactic sugar
             | for `for` loops, and it's also meant to simplify actions.
             | There are functional equivalents to many small patterns of
             | code that occur often - for instance                   lst
             | = []         for element in range(10):
             | lst.append(element * 2)
             | 
             | Is a very common pattern, that can be expressed with less
             | typing (and less mental overhead, when you become used to
             | it) by                   lst = list(map(lambda x: x * 2,
             | range(10)))
             | 
             | Similarly, another very common mini-pattern is
             | total = 0         for el in range(10):             total +=
             | 3 * el
             | 
             | Which can be more swiftly expressed by
             | total = reduce(lambda acc, el: acc + 3 * el, range(10))
             | 
             | These examples are trivial, but once you start using these
             | higher level syntactic sugar-like constructs, you often
             | find that code tends to fit together more nicely and in
             | ways that make more sense, even if only because you used a
             | filter operation before the map instead of writing another
             | level of nested `if` statements inside a loop body. Code
             | gets easier to follow, not unlike how it's easier to reason
             | about the behavior of a `for` loop than it is to keep a
             | bunch of `goto`s in your mental model of what the code does
             | while at the same time thinking about whether the business
             | logic part of it makes sense.
        
               | wruza wrote:
               | Tbh, I get your imperative examples instantly but my mind
               | struggles to autograsp these multilevel functional parts
               | like list(map(lambda. Too much noise, I have to think
               | through it to get it.
               | 
               | I'd prefer a loop with ifs and continues/breaks.
               | 
               | It may be a lack of experience or habit, but then I _can_
               | write code like that (and worse), and it doesn't make any
               | sense to me. Don't get me wrong, not that I refuse to use
               | maps or filters or folds, but not that I want to make a
               | whole program of them either. They have their place where
               | factoring-out a block of code feels stupid, but if I had
               | something like:                 [1, 2, for (x of xs) {
               | if (cond) {emit x}       }]
               | 
               | I'd never bother with these function-al things. It's not
               | FP that is rich, it's a traditional imperative syntax
               | that sucks. Paradigm shift is not equal to usage out of
               | [in]convenience.
        
               | mrkeen wrote:
               | [1, 2, for (x of xs) {           if (cond) {emit x}
               | }]
               | 
               | What are 1 and 2 doing? What is emit? Where does x _go_ ?
               | 
               | Is the above code just:                   filter cond xs
               | ?
        
               | wruza wrote:
               | It results into [1, 2, ...(some xs satisfying cond)].
               | Emit does just that - emit another value into a context
               | where for-expr was used. It emits some of x-es into that
               | array literal.
               | 
               |  _filter cond xs_
               | 
               | More like 1:2:filter cond xs.
        
               | atraac wrote:
               | > Tbh, I get your imperative examples instantly but my
               | mind struggles to autograsp these multilevel functional
               | parts like list(map(lambda. Too much noise, I have to
               | think through it to get it.
               | 
               | That's exactly why most FP languages have pipe operator,
               | so it's incredibly easy to read.                 lst =
               | range(10)              | map(fn x -> x * 2 end)
               | | map(etc...)
               | 
               | or                 total = range(10)              |
               | reduce(0, fn elem, acc -> acc + (elem * 3) end)
        
               | wruza wrote:
               | That doesn't change much for my read ability. It even
               | reads more imperatively, like: I take a range of 0 to 10,
               | map it over x * 2, map it over... What do I get? A
               | mapping? Maybe?
               | 
               | Meanwhile, a for loop is straightforward, you go from 0
               | to 10 and append a double or add a triple of x to an
               | accumulator. I appended/added them, that's what I get.
               | It's like my brain somehow follows {} scopes and
               | understands their local envs with no effort.
               | 
               | If this syntactic style works for you without this
               | friction, nice. But it doesn't work for everyone and I
               | suspect that this FP/PP is biased by this effect at both
               | sides.
        
               | atraac wrote:
               | > What do I get? A mapping? Maybe?
               | 
               | A mapped list/enumerable it was originally given. You
               | don't think what you get when you add two numbers, don't
               | you? Language just works certain way. Not understanding a
               | simple building block of a language isn't a valid
               | argument against it. All you essentially say is that you
               | got so used to OOP concepts that anything else is hard to
               | read. And it's ok, it's the same way for everyone... But
               | it's not a valid argument to say that "fUnCtIoNAL bAd".
               | The whole thing here boils down to what you already said
               | - lack of experience.
               | 
               | My honest advice is - try to learn one functional
               | language, like honestly learn and understand it, try
               | writing something with it. It really does expand
               | horizons.
        
               | jve wrote:
               | > I can write code like that (and worse), and it doesn't
               | make any sense to me
               | 
               | I'm learning FP and I see value with writing code with
               | map, reduce etc as those are expressions instead of
               | statements. Expressions guarantee you have a result of
               | particular type (with possible side effects if you
               | prefer), but statements DO side effects. The loop may or
               | may not insert some value into resulting list because
               | some branching happened or you forgot some else
               | condition, with map you guarantee you get same number of
               | objects of particular type back.
               | 
               | Plus that enables composition (like in C# LINQ) - by not
               | extending some loop with different kind of
               | responsibilities but just passing result to next function
               | that modifies/filters the result.
               | 
               | https://fsharpforfunandprofit.com/posts/expressions-vs-
               | state...
        
               | im3w1l wrote:
               | For what its worth, the pythonic solution is
               | lst  = [x * 2 for x in range(10)]
        
           | Gordonjcp wrote:
           | Why is anything better than GOTO?
           | 
           | You use GOTO all the time, even if it's wrapped in an
           | abstraction that makes its intentions less clear.
        
       | _rm wrote:
       | Its greatest strength I see is its simplicity. OOP gives a lot of
       | latitude to overcomplicate solutions, and I've found it tends to
       | obscure more obvious solutions to certain problems, e.g. reaching
       | for inheritance to modify behaviours instead doing it by passing
       | functions as arguments, especially among less experienced team
       | members.
       | 
       | The biggest problem in software development is the slow down of
       | value output over time caused by accumulating complexity.
       | Anything that can help keep complexity down is a big win for long
       | term value output.
        
         | kalekold wrote:
         | If OOP is over-complicating your code, you're using it wrong.
         | OOP is a tool to manage complexity.
         | 
         | Functional programming, in my experience, created much more
         | complicated code because it seems like the authors like to be a
         | clever as possible.
        
           | epgui wrote:
           | Are you confusing "complicated" with "unfamiliar"?
        
           | prmph wrote:
           | Indeed. Although I have mostly stopped using OOP in most of
           | my code, I sometimes encounter certain classes of problems
           | that are exceedingly complicated to solve in a purely
           | functional way, but that are a breeze to solve using OOP,
           | believe it or not.
           | 
           | One can mix functional and OOP code well by
           | compartmentalizing the parts of the code that are in OOP
           | style, and situating it in an overall functional context. For
           | example, the methods of a class can certainly be written in a
           | very functional style, and classes themselves can be
           | instantiated within functions.
           | 
           | The mark of a skilled developer is to know which paradigm is
           | the best to solve a particular problem, just like the choice
           | of a data structure can greatly affect simplicity of code to
           | address a problem.
        
             | yen223 wrote:
             | > I sometimes encounter certain classes of problems that
             | are exceedingly complicated to solve in a purely functional
             | way, but that are a breeze to solve using OOP, believe it
             | or not.
             | 
             | What kinds of problems, if I may ask?
        
           | _rm wrote:
           | Once you zoom out to the bigger picture of dozens of devs
           | writing the code rather than yourself, its more a matter of
           | "statistically, if I recommend functional over OOP, how
           | simple will the code be a year from now".
           | 
           | But granted it needs to be part of a broader pressure to keep
           | things simple, otherwise devs will like you say, find a way
           | to overcomplicate.
        
         | pmontra wrote:
         | I agree. As an example having to create a class for bags of
         | methods that don't fit naturally anywhere is bad. I also
         | despise all the manager, factory, service, command things that
         | emerge more often in OOP projects than in functional ones. I
         | know that they denote well known patterns (if used in that way)
         | but it's clutter, boilerplate, noise around the code that does
         | the job. However functional only is not necessarily better in
         | my experience.
         | 
         | Some context. I'm sure I'm biased by a number of factors. One
         | is that I started programming a long time ago in C and I was
         | passing around structs with data and function pointers, so
         | objects. Another one is that I used a number of different
         | languages, currently Elixir, Python, Ruby, some JavaScript,
         | often in the same week for different customers: I like easy to
         | understand code because I this kind of projects with sparse
         | teams is easier to maintain than layer over layer of heavily
         | engineered one (so factories, metaprogramming, etc.) Third, I
         | end up using a minimum common denominator of all those
         | languages plus inescapable and/or great features: I wish all
         | languages had Elixir's pattern matching. This approach works
         | and it reduces the context switch between projects.
         | 
         | So, when I'm coding in Elixir sometimes I have to create large
         | data structures and pass them around, piping them to
         | Module1.fn1, Module2.fn2, etc. It's more or less the same than
         | composing methods in OOP, just different syntax. Sometimes
         | those modules become bags of functions too. What's more
         | difficult to do in OOP is to engineer a class to accept
         | arbitrary meaningful methods. In Ruby I often code methods that
         | return a hash (Python dict, JS object) and create a pipeline of
         | .map.map.map in their caller, like a |> pipeline in Elixir.
         | 
         | I prefer mixed paradigm approaches, where one can create the
         | few classes needed to represent the few data types that are
         | objects (Elixir's and Erlang's GenServer) and code everything
         | else as functions. I have a couple of Django projects where the
         | only classes are the mandatory database models and management
         | commands. Everything else is functions in modules. That would
         | be much more pleasant to code in Elixir (if it had classes
         | instead of those noisy and uninformative handle_call,
         | handle_cast, start_link.) Ruby has modules too but for some
         | reason customers really like to create classes for everything,
         | even two method ones like                 class Command
         | def initialize(args)           ...         end         def run
         | ...         end       end            Command.new(args).run
         | 
         | which are quite funny to look at. That should be
         | command(args)
        
           | Tainnor wrote:
           | > Ruby has modules too but for some reason customers really
           | like to create classes for everything, even two method ones
           | like [...]
           | 
           | Encapsulation and extraction of complex functionality (yes,
           | you should not do it for trivial one-liners).
           | 
           | In Ruby, classes get used a lot for this because, uh, why
           | not, but you might as well just have a module method - it's
           | just that the way modules are used in Ruby makes this
           | _slightly_ awkward because Ruby is after all biased towards
           | "everything is an object".
           | 
           | But in, say, Haskell I might write instead:
           | module Command            run :: [String] -> IO ()       run
           | = ...            -- some other file            import
           | qualified Command            ...       Command.run args
           | 
           | (not that "Command.run" looks like super idiomatic code in
           | Haskell or anything like that, probably you'd structure your
           | code differently, but it's the general principle)
        
       | epgui wrote:
       | Every FP advocate I know comes from an imperative/OOP
       | background... None of them are juniors. None of the "FP skeptics"
       | (or people parroting an obvious variant of uninformative "right
       | tool for the job") I know come from an FP background.
       | 
       | People only seem to convert one way and not the other. And is it
       | really a surprise that the vast majority of people resist change
       | / doing things differently?
        
         | gjulianm wrote:
         | Without going into the core of whether FP is better or not, if
         | OOP/imperative is what 99.9% of people start with, you'll
         | expect to have both FP advocates and skeptics coming from that
         | background. It's just that FP skeptics have tried it and gone
         | back.
         | 
         | In other words, people only convert one way because it's the
         | only way most people can convert.
        
           | epgui wrote:
           | I understand what you're saying, but my point is that the
           | near totality of FP criticism comes from people who don't
           | know what they're talking about.
           | 
           | ie.: you need to be very familiar with something before you
           | can reasonably criticize it.
        
             | nyanpasu64 wrote:
             | When I go back to my old map/zip/method-chaining Rust code
             | from a year or two ago, I regret doing so and wish I had
             | written code as imperative sequential operations (looping
             | over numeric ranges and container items, branching, and
             | matching) like I write and understand today.
        
         | mrkeen wrote:
         | Hear, hear.
         | 
         | When I program, I like to use:                 { functions,
         | types }
         | 
         | When FP gets bolted onto a mainstream language after the fact,
         | you get to program with:                 { classes, mutability,
         | side-effects, nulls, functions, types }
         | 
         | Then the FP skeptics think it's too complicated, and just want
         | to go back to:                 { classes, mutability, side-
         | effects, nulls }
        
           | epgui wrote:
           | Why not just use COBOL and Gotos while we're at it? It was
           | "the right tool for the job" for decades until the OOP
           | religion took over! /in_jest
        
             | mrkeen wrote:
             | Sure /s.
             | 
             | But seriously I dislike the notion that FP is somehow a
             | _successor_ to OOP, like you have to keep piling
             | abstractions onto OOP until it becomes FP!
             | 
             | If you do it that way, you end up with map()
             | implementations like:                   public final <R>
             | Stream<R> map(final Function<? super P_OUT, ? extends R>
             | mapper) {             Objects.requireNonNull(mapper);
             | return new StatelessOp<P_OUT, R>(this,
             | StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED |
             | StreamOpFlag.NOT_DISTINCT) {                 Sink<P_OUT>
             | opWrapSink(int flags, Sink<R> sink) {
             | return new Sink.ChainedReference<P_OUT, R>(sink) {
             | public void accept(P_OUT u) {
             | this.downstream.accept(mapper.apply(u));
             | }                     };                 }             };
             | }
             | 
             | Ain't nobody got time to read that. Step _back from_ OOP
             | before putting in the FP and you can get map() looking
             | like:                   map _ []     = []         map f
             | (x:xs) = f x : map f xs
        
               | epgui wrote:
               | Personally I do see FP as a "successor" to OOP, but not
               | in a strictly constructive or chronological sense.
               | 
               | Building FP functionality with classes sounds just as fun
               | as building java classes with assembly.
        
               | _old_dude_ wrote:
               | The problem of the Java code above is that it tries to
               | serve many masters, one of them being the JIT, i.e. the
               | code is written that way so the JIT can fully inline the
               | whole code.
               | 
               | The first "final", the "StatelessOp", the
               | "StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT",
               | the "int flags" are all here because of performance.
        
               | teh64 wrote:
               | Well your second example relies for speed and efficiency
               | on Haskell being lazy. If you did e.g. a map -> filter ->
               | sum chain, the performance is not that great without lazy
               | evaluation guaranteed by Haskell's implementation, which
               | can complicate code in other scenarios or in the
               | complexity of the compiler. OCaml is also an FP language,
               | and the second example would be almost the same text, but
               | with much worse performance.
               | 
               | Also, Python is an OOP language, but a simple map
               | implementation there is not much more verbose:
               | def map(function, items):             if len(items) != 0:
               | return [function(items[0]), *map(function, items[1:])]
               | return []
        
               | epgui wrote:
               | I think the more pythonic way would probably be to use a
               | list comprehension:                   def map(f, items):
               | return [f(i) for i in items]
               | 
               | These differences are all more about specific languages
               | than about FP per se, however.
        
           | _old_dude_ wrote:
           | Yes, this rings a bell :)
           | 
           | But usually the issue is that people talk about OOP vs FP
           | without specifying the scale, by example the Java stream API
           | hide the mutations / side effects (not unlike Haskell monads
           | do), so you can use                   { record, stream,
           | functions, types }
           | 
           | But internally it's still                   { mutability,
           | side-effects }
        
       | light24bulbs wrote:
       | How are the types not totally screwed up in this kind of pattern?
       | I get that this is JS, but since most of us at the level to be
       | reading this post actually write TS, isn't it true that most of
       | those transformations actually modify the type of the object, and
       | therefor each would need to have a slightly different
       | intermediary type?
       | 
       | When I actually have this problem, I usually define the input as
       | an interface and the output as another interface(maybe extending
       | the input interface).
       | 
       | Then I write a SINGLE function that calls those other functions,
       | collects the data into variables, and then builds a new object of
       | the new data type, and then returns that.
       | 
       | Maybe I'm missing the point here.
        
       | substation13 wrote:
       | Excuse me sir, do you have a moment to talk about _Functional
       | Programming_?
       | 
       | I love FP and I think it makes writing robust software easier.
       | However, I don't think the benefits can be explained well. The
       | only way to see it is to give it an honest try - in a true
       | functional language. This is too much of an upfront commitment
       | for the unconvinced.
        
       | sidlls wrote:
       | "Instead, the most intelligent coders I knew tended to take it
       | up; the people most passionate about writing good code."
       | 
       | Ah, yes, the most intelligent people tended to take it up,
       | therefore if I take it up I, too, am intelligent.
       | 
       | That single line in the article encapsulates everything wrong
       | with FP zealots' approach to their advocacy.
        
         | dsnr wrote:
         | The gazillion of lines of imperative C/C++ code out there that
         | every OS runs on, are probably written by less than intelligent
         | people.
        
           | goatlover wrote:
           | Like Linus Torvalds. Lispers tend to make similar claims. So
           | does Alan Kay about Smalltalk. Yet most of the world runs on
           | top of C/C++, or COBOL (or Java) for financial transactions
           | and Fortran for heavy duty numerical calculations. Not that
           | FP, Lisp and ST don't have their advantages. They clearly do.
           | But their supremacy is overstated when it comes to code that
           | runs the world.
        
             | senand wrote:
             | That doesn't mean the imperative languages are "better",
             | though, just more popular. I recommend the following video
             | titled "Why isn't Functional Programming the Norm?":
             | https://www.youtube.com/watch?v=QyJZzq0v7Z4
        
           | npc12345 wrote:
        
           | gpanders wrote:
           | Ah yes, OS development, a domain famous for attracting stupid
           | people.
        
           | bordercases wrote:
        
         | didibus wrote:
         | Do you mean that talent is required to leverage FP effectively?
         | 
         | Kind of like how a faster car in the hands of a less talented
         | driver won't make them faster, but might just cause them to
         | crash? Whereas a talented driver would pick a faster car and
         | actually benefit from it?
         | 
         | Personally I think it's not so much about intelligence or
         | talent, but passion. In think the developers who demonstrates
         | that they've learned and tried more development techniques and
         | styles, that shows a passion and interest towards software
         | development, engineering and comp-sci. That passion is often
         | key to success and long term performance.
         | 
         | There's probably a cutoff between talent and passion, where
         | passion alone probably has some limits, but also where talent
         | alone has limits as well. If you find someone with both though,
         | that's a pretty good sign.
         | 
         | The question is, are talented developers drawn to FP, or is it
         | passionate developers that are? Or those that have both?
         | 
         | And the other question is, can FP make someone more talented?
         | Can it make them more passionate?
        
         | galaxyLogic wrote:
         | People often confuse intelligence with complexity.
         | 
         | Yes you have to be intelligent to understand complex problems
         | and complex solutions. But just because you are intelligent
         | enough to understand a complicated solution, does not mean the
         | solution is "intelligent".
         | 
         | True intelligence is about coming up with solutions where
         | complexity is minimized.
         | 
         | Even though an intelligent person can understand a complicated
         | solution the complexity of a solution strains even the most
         | intelligent programmer. It takes time to ensure yourself that
         | the solution is correct. Whereas with a simple solution that is
         | easy. It takes intelligence to find a solution that is simple
         | and thus easy.
        
           | kaba0 wrote:
           | That's a great take, but I have to mention that I disagree
           | with a statement I may have only read into the thread: FP is
           | not more complex just for the sake of it.
        
             | yCombLinks wrote:
             | I think FP's niche popularity is primarily because of it's
             | complexity. The complexity of it makes certain types of
             | people feel smart, so they love it.
        
           | NaturalPhallacy wrote:
           | Completely agree. My favorite example of this is Douglas
           | Adams' description of flight (or orbital mechanics): "Throw
           | yourself at the ground and miss."
        
       | jasmer wrote:
       | It's a bit of a canard.
       | 
       | The benefits of FT are mostly things like statelessness, no side
       | effects.
       | 
       | And it's almost better to talk about it in those terms, and
       | introduce concepts into imperative programming.
       | 
       | When people say 'functional core (aka libs) and imperative for
       | the rest' it's ultimately what they mean.
       | 
       | Applying FP universally creates weird code and it becomes
       | pedantic and ideological.
       | 
       | I wouldn't even use the example in the article almost nothing is
       | gained.
       | 
       | Try to reduce state, use immutable objects as much as possible /
       | where reasonable, make reusable function which naturally have
       | fewer side effects etc..
       | 
       | I think that the material benefit of FP is in partial application
       | of some elements of it, and unfortunately that doesn't create
       | nice academic threads for people to talk about. It's more like
       | applied know-how, than theory.
        
         | canadianfella wrote:
         | What do you mean by "canard"?
        
           | zabzonk wrote:
           | false report
        
       | rvalue wrote:
       | i will say one thing about functional programming. it does feel
       | amazing to write all those stateless functions and using all
       | kinds of operators.
       | 
       | here is where one gets into trouble, reading functional code.
       | while it may look better when you write it, try reading your own
       | code after a few weeks. you will appreciate it much more when
       | your control flow in a significantly large enterprise application
       | is through bunch of ifs and imperative loops than scattered
       | across various functions and operators.
       | 
       | another problem, debugging. when your inputs cross various
       | function boundaries, no matter how smart IDEs you have, you end
       | up messing around adding impurities to your pure functions and
       | adding watches with conditions all over the place.
       | 
       | lastly, all that lux code does hide a significant problem.
       | Performance. I don't know about javascript but all those
       | temporary objects one keeps creating for the pursuit of
       | statelessness is maddening. i don't know if there is anything
       | characteristically different about a language like Haskell which
       | handles this problem. Does it end up creating new objects every
       | time for e.g. a map is called like in this example to update all
       | the attributes?
        
         | tome wrote:
         | That's interesting, because Haskell is the first language I
         | have found in which I can write code, come back to it six
         | months later, and still understand it. I never managed to do
         | that in C, C++, Java, Perl or Python.
        
         | mrkeen wrote:
         | > Does it end up creating new objects every time for e.g. a map
         | is called like in this example to update all the attributes?
         | 
         | No. This is optimised away.
         | 
         | It's yet another reason why it's frustrating to see FP-like
         | things bolted onto mainstream imperative stuff. You can't
         | optimise away 'mostly functional' code. Wrapping a Set with an
         | UnmodifiableSet isn't the same thing as (f x) + (f x) == 2 * (f
         | x)
        
       | gtirloni wrote:
       | I didn't understand what was the point of the introduction with
       | so many words like that.
       | 
       | Author describes functional programming zealots and seems to
       | imply it's all annoying because of all the abstractions, then
       | proceeds to do exactly that while calling it "the good parts".
        
       | commandlinefan wrote:
       | The main problem with functional programming is that most
       | programmers are too incompetent to use it. It's complicated, the
       | way calculus and music are. While it's sort of a safe assumption
       | that anybody outside of the actually learning disabled, with
       | enough concentration, could buckle down and learn it, most people
       | - so most programmers - won't. Most programmers won't advance
       | past procedural code - that's why Java programmers love the
       | singleton pattern and the Spring "framework" so much: it lets
       | them write and think in simplistic procedural form but pretend
       | they're using an object-oriented programming language. (And if
       | you can't even comprehend OO, you _definitely_ can 't comprehend
       | FP).
        
         | 62951413 wrote:
         | I'm still waiting for a FP equivalent of the original GoF book
         | to learn it from.
         | 
         | * https://leanpub.com/sofp is impressive but is in a different
         | category
         | 
         | * https://www.manning.com/books/functional-and-reactive-
         | domain... is the only one I know which was trying to discuss
         | building real life software
        
       | dgunay wrote:
       | An aside that I've been wondering about for a while with FP. I
       | tend to use a lot of tools that do things like cyclomatic
       | complexity analysis, test coverage metrics, etc.
       | 
       | It seems like one goal of this style of FP is to abstract away
       | control flow itself - why bother with if-statements when you can
       | compose automatically short-circuiting monadic APIs like Option
       | and Result? An admirable goal that I am 100% in favor of. However
       | I feel like it might also obfuscate untested branches in source
       | code and artificially minimize computed cyclomatic complexity if
       | the tools are not aware of these control flow abstractions.
       | 
       | I guess it's not super important in the grand scheme of things
       | (I'm well aware of cyclomatic complexity's dubious usefulness as
       | a metric).
        
       | BerislavLopac wrote:
       | When it comes to programming, pretty much everything boils down
       | to two key elements:                 - Some kind of
       | data/information, in some (digital) form of one structure or
       | another.       - Methods, processes and operations that
       | transform, transport and do other things to that data.
       | 
       | For example, in OOP, those two elements are generally combined
       | together in organisational units ("objects"); on the other hand,
       | in functional programming they are strictly separated.
       | 
       | Each of those paradigms - and many others - are just tools in our
       | arsenal to achieve our goals, and neither is intrinsically better
       | than the other. Depending on the context and environment that we
       | are operating within, each has its advantages and disadvantages;
       | some are better suited than others _in certain cases_.
        
         | thaway34453 wrote:
         | You can marry FP with object oriented notation, see UFCS or
         | Scala, or lenses.
        
           | BerislavLopac wrote:
           | Of course you can, and that just strengthens my point. :)
        
       | quickthrower2 wrote:
       | > What we care about is "can we deliver better code, faster"
       | 
       | Strawman! Most coders, even staunchly "imperative" ones care a
       | lot about tech debt, tidyness and code quality. That is why
       | things like SOLID and design patterns are popular. For better or
       | worse good programmers are proud of their code, and I don't meet
       | too many who feel they need to "ship faster". Product people
       | might want that though.
        
       | kyberias wrote:
       | Please fix the font used for code examples. Unreadable.
        
       | ergonaught wrote:
       | I have grown impatient with writing which purports to educate or
       | inform people who do not understand a topic yet is completely
       | incomprehensible unless one understands the topic.
       | 
       | Practice some "Feynman technique" on your subject, or resign
       | yourself to producing a suggested reading list of works that
       | actually explain the topic, or please for the love of cognition
       | stop masking signal with your noise.
        
       | roenxi wrote:
       | If you start with a program, see it as a block of logic that can
       | be separated into parts with cuts in many different places.
       | Choose the cuts so as to leave it a composition of functional
       | programming abstractions. Then it is easy to reason about and it
       | is possible to teach others to code in the same way. This is a
       | benefit for functional programming - a promise of consistency in
       | thought and style that is easy to debug.
       | 
       | The argument I read in this article seems to be going in that
       | direction, but I'm not sure it is being presented clearly. The
       | semi-monoid functors are a fair way down in the weeds and not
       | really what people should focus on when deciding why functional
       | programming is great. Unless they really like abstractions in
       | which case more power to them.
        
       | inawarminister wrote:
       | I'm having a good time doing Data-Oriented Programming (which is
       | applying Clojure-style programming to other languages, in my case
       | Python).
       | 
       | IMO, chaining functions together rather than mutating objects and
       | variables seem to be the most Pareto efficent takeaway from FP
       | (at least in the Scheme/Clojure style, haven't tried F#/OcaML or
       | Haskell). And HOP, though Python has native support for map and
       | reduce and filter in the last few years, so great enough.
       | 
       | And to be honest when I try to do something complicated in
       | Clojure I end up blowing the stack anyway. Recursion is a bit too
       | hard to grasp for non-programmers like me.
        
       | fleddr wrote:
       | I'm sure this is a wonderful intellectual exercise in computer
       | science and math, but if this is to be the advertisement in favor
       | of functional programming, I wouldn't consider myself a customer.
       | 
       | You start out with code that will not win any beauty awards but
       | it gets the job done. It's easy to understand by programmers of
       | any seniority, it's simple to debug and reasonably easy to put in
       | an automatic unit test.
       | 
       | Next, you add all kinds of vague, poorly named meta utilities
       | that don't seem to solve any tangible real world problem. You
       | even mess with built-in JS methods like map. The code is now
       | harder to understand and more difficult to debug.
       | 
       | A massive pain is added for some theoretical purity that few even
       | understand or will benefit from. I'll double down on my rebellion
       | by stating that the portability of code is overrated.
       | 
       | Here we're writing code to format notification objects. In our
       | overengineering mindset, we break this down into many pieces and
       | for each piece consider reusability outside this context to be of
       | prime importance.
       | 
       | Why though? Why not just solve the problem directly without these
       | extra self-inflicted goals? The idea that this is a best practice
       | is a disease in our industry.
       | 
       | Most code that is written prematurely as reusable, will in fact
       | never be reused outside its original context. And even if it is
       | reused, that doesn't mean that outcome is so great.
       | 
       | Say that the sub logic to format a user profile link turned out
       | to be needed outside this notification context. Our foresight to
       | have made it reusable in the first place was solid. Now two
       | completely different functional contexts are reusing this logic.
       | Next, the marketing department goes: well actually...you need to
       | add a tracking param specifically for links in the notification
       | context, and only there.
       | 
       | Now your "portability" is a problem. There's various ways to deal
       | with it, and I'm sure we'll pick the most complicated one in the
       | name of some best practice.
       | 
       | After 20 years in the industry, you know how I would write the
       | logic? A single method "formatNotification". It wouldn't weirdly
       | copy the entire object over and over again, it would directly
       | manipulate the object, one piece at a time. Error checking is in
       | the method as well. You can read the entire logic top to bottom
       | without jumping into 7 files. You can safely make changes to it
       | and its intuitive to debug. Any junior would get it in about 2
       | minutes.
       | 
       | Clear, explicit code that requires minimum cognitive parsing.
        
         | foobiekr wrote:
         | One of the things that you imply is another issue: inheriting
         | someone's functional code is brutal. I'd rather inherit
         | mediocreville php than decipher the "clever" code that someone
         | who got excited by scalaz polished for weeks.
        
         | oldboyFX wrote:
         | Thank you for writing this. I've come to exactly the same
         | conclusion after a decade of building and delivering complex
         | tangible applications which others have to maintain after I'm
         | gone.
        
           | fleddr wrote:
           | Thanks for the support.
           | 
           | I used to live all the best practices, but over time learned
           | that the number one enemy in a codebase is complexity. 90% of
           | software development is maintenance. People doing maintenance
           | are lowly productive because the vast majority of time is
           | spent on trying to understand how things even work,
           | debugging, and making changes in a way that is safe.
           | 
           | The reason code is complex are abstractions and dependencies.
           | Many of which are of a questionable or negative value and
           | never deliver their imagined benefits. Hence, instead of
           | "abstract by default" and seeing DRY as some religion, I
           | abstract when value is real, proven and outweighs the massive
           | downsides of doing so.
           | 
           | Imagine that we'd need to write a recipe. Sane and pragmatic
           | people would write it as a sequential step of instructions.
           | If a software engineer were to write one, just to follow the
           | recipe you'd need to have 23 additional papers each
           | describing a sub step referred to from the main instructions.
           | Next, we would abstract each substep into "Motion" and
           | "Activity" generalizations. This way, you can reuse "Motion"
           | when you walk your dog later that day. Quite obviously,
           | motions can fail so we extend it with a MotionError, which is
           | a sub class of Error. MotionError has a Logger interface.
           | These 3 super abstractions are useful, instead of just
           | directly saying that you failed a recipe step, we can now
           | apply failure wherever we want, even onto life itself. Since
           | recipes are written in a language, we should abstract
           | Language, itself a composition of sentences, words,
           | characters and glyphs with a Dictionary interface, which
           | itself is an array of Name and Value objects, that we might
           | as well generalize as Thing.
           | 
           | Anyway, those were recipe steps. Next, let's do ingredients,
           | also known as immutable multivariant singletons. But not
           | really, because as we follow the instructions, the
           | ingredients morph into something else, which we'll solve with
           | a Morp object, which holds an interface StateChange,
           | consisting of two State objects, which are Things. A
           | ThingsIterator takes care of handling multiple things but not
           | in a way you'd expect, we'd override map() because I really
           | feel my Thing is special. Thinking of recipes, they can
           | potentially come from any source so we'll implement Verbal
           | (an abstraction of Language), Database and the jungle that
           | comes with it, all neatly wrapped into MoreThings.
           | 
           | Next we redo all of his by writing unit tests, so that our
           | software that by now implements most of the universe is
           | qualitative. It's math.
           | 
           | Or...we can just write the damn recipe.
        
             | naasking wrote:
             | Your beef appears to be with over-abstraction and not
             | functional programming. FP generally makes debugging much
             | easier because the state of the system isn't changing in
             | unexpected ways underneath you, so you only need to look at
             | local state.
             | 
             | A "functional" recipe is just as simple and straightforward
             | as an "imperative" recipe.
             | 
             | Over-abstraction on the other hand, can be introduced with
             | imperative object oriented programming just as easily as
             | with functional programming.
        
             | avgcorrection wrote:
             | Hahaha, this is delightful :)
        
             | tome wrote:
             | It's funny because I completely agree with you principles
             | but completely disagree with, what I think is, your
             | conclusion, that functional programming should be eschewed.
             | On the contrary, pure FP, specifically in Haskell, is the
             | only way I've ever found to reliably put your principles
             | into practice.
        
             | zabzonk wrote:
             | agreed with your first post, much less so than this one,
             | because it is based on analogy. recipes are really not like
             | programming. when i try a new recipe, i normally read the
             | description to see what i am going to get out of it, and if
             | it appeals, give it a bash, without any accuracy.
             | 
             | for example, elizabeth david (never a one for accurate
             | measurements) has a great recipe for beef with olives,
             | which comes down to onions, garlick, bay leafs (other herbs
             | to taste) olive oil, lemon peel, beef, black olives, red
             | wine. then just cook them. any experienced cook will have
             | no probs with this - the interesting thing is the
             | combination of beef and olives. all the quantities are
             | somewhat irrelevant and can be adjusted to taste.
             | 
             | whereas a computer program must be pin-point accurate in
             | all details
             | 
             | analogies == bad. imho
             | 
             | sorry i went on a bit there
        
         | sfvisser wrote:
         | You're really fighting the wrong fight here. FP is not about
         | prematurely writing reusable code.
         | 
         | It's about recognizing patterns in code that exist all over the
         | place and _reusing those existing patterns_ for the new code
         | you 're writing. This way you can break your new feature into
         | say 20% newly written domain specific code and 80% reusing
         | existing patterns. Patterns that help with composition,
         | enforcing invariants, simplifying writing test-cases, and more
         | clearly signaling intent.
         | 
         | For example, if you provide a monad instance for your
         | "formatting notification objects" I will probably understand
         | how to use your library without even reading a single line of
         | implementation at all. Just by scanning a few type signatures.
         | 
         | This way you and your team mates have a huge head start in
         | understanding your new addition to an existing code base. This
         | is a great win for everyone!
        
           | salawat wrote:
           | ...except that has nothing to do with FP and everything to do
           | with... actually reading code.
        
           | fleddr wrote:
           | I'm not fighting, only offering an opinion. We simply
           | disagree at a fundamental level.
           | 
           | My first and main point is that 80% of software developers,
           | the silent majority of so-called "bread programmers", do not
           | grasp these concepts. So even if the concept is great, it
           | doesn't matter.
           | 
           | Second, and this is purely based on experience, I do not
           | subscribe to the idea that your envisioned way of writing a
           | new business feature is very realistic or useful. It leads to
           | dependency hell, difficult to understand code, which is
           | difficult to debug. I don't even subscribe to the idea
           | (anymore) that if you're asked to implement a business
           | feature, that it is implied that you should write it as if it
           | can be torn apart and used for some imagined other feature.
           | Nobody asked for that, we just made that up.
           | 
           | One can say that I've become a DRY infidel. I don't expect
           | you to agree, very few would agree. Yet I've arrived here for
           | a reason: 20 years of headaches looking at "best practice"
           | codebases.
        
         | spc476 wrote:
         | You can apply some FP notions to any code base:
         | 
         | 1. Don't use globals. Zero global variables should be the goal,
         | that way, you avoid "spooky action at a distance" where some
         | code here changes a global that changes the behavior of code
         | over there. A function that avoids global variables is easier
         | to deal with than one that doesn't. If you feel you need to use
         | a global, think about why you need one before adding it. Maybe
         | you can avoid it.
         | 
         | 2. Parameters to functions are immutable. That way, you won't
         | have to worry about data changing during a function call. If
         | the parameter can be mutated, can you signal the intent in the
         | function name or signature, so the programmer knows that to
         | expect? Generally, try to avoid changing parameters in a
         | function.
         | 
         | 3. Separate I/O from processing. Do input, do your processing,
         | then output. God, I wish the major component I worked on did
         | that (concurrent DB requests)---it would make testing the
         | business logic so much easier as it can be tested independently
         | from the I/O.
         | 
         | Those three things can be done in any language, and just by
         | doing those three things, you can most of the benefit of FP
         | without the mathematical jargon (Monads? How do they work?).
         | There's no need for over-engineered code, and you can be as
         | explicit as you like while keeping the cognitive aspects to a
         | minimum.
        
           | fleddr wrote:
           | Well done. Your comment shows actual FP best practices and
           | their immediate, significant advantages. And you did so
           | succinctly.
        
         | wtetzner wrote:
         | > It wouldn't weirdly copy the entire object over and over
         | again, it would directly manipulate the object, one piece at a
         | time.
         | 
         | I think this is the only part I disagree with. Immutable data
         | types make it much easier to understand code, because
         | everything is local. You don't have to worry that some other
         | part of the code base might have a reference to this object,
         | and could be manipulating it out from under you.
        
         | draw_down wrote:
        
         | ozim wrote:
         | I agree - problem is loads of people think they should write
         | framework and not a simple CRUD app.
         | 
         | I remember one meeting where clueless business person told
         | developers (including me) that we need an * _abstract*_
         | solution for a problem.
         | 
         | It took me quite some hours to explain to other devs that for
         | this business person abstract solution is not what they think
         | it is. Business person wanted CRUD app where they could
         | configure names for database entries where developers wanted to
         | make some fancy data types to be used with parametric
         | polymorphism.
        
         | jimbokun wrote:
         | Sounds like Go is your ideal language.
        
       | commitpizza wrote:
       | Interesting article with an interesting writing style, I may pick
       | up the book even if I suck at reading books!
       | 
       | I didn't start as a skeptic and really think functional
       | programming looks beautiful and is very useful in preventing side
       | effects. However, in most practical situations I've found over
       | the years functional programming to be harder to understand and
       | debug when stuff goes wrong.
       | 
       | In javascript in particular, functional programming is very nice
       | but at the same time usually way more ineffecient so for many
       | tasks I tend to go back to normal for loops just because it's
       | that much faster.
       | 
       | I had a collegue that wrote a lot of functional code and his code
       | was extremely hard to follow and understand. Even if it was
       | beautiful figuring out where the system went was the hard part
       | and I had to go to the function decleration, understand it, move
       | on to the next until I found whatever the issue was. When I found
       | the issue, I couldn't easily fix it because the next function
       | called was expecting the data structure to behave in a specific
       | way so for one issue once I had to change basically every
       | function called before and after which was way more tedious then
       | if it would have been more sequential.
       | 
       | I don't know. There is something to say about functional
       | programming but lately I have kind of tilted back into the more
       | standard approach. Functional programming is a lot more beautiful
       | in practically every implementation I've seen but the standard
       | approach is, in my experience, usually more useful in practical
       | terms.
        
         | zozbot234 wrote:
         | > I had a collegue that wrote a lot of functional code and his
         | code was extremely hard to follow and understand.
         | 
         | That's not a problem with functional code, it's about badly
         | designed abstractions. You get the same issues in garden-
         | variety OOP codebases, only to a far greater extent.
        
       | valenterry wrote:
       | There really needs to be a more clear separation between
       | functional programming (a very unclear and ambiguous term) and
       | pure functional programming (formerly just functional
       | programming, short and well defined but with huge
       | implementations)
        
         | mrkeen wrote:
         | Yes, but pure means different things in different contexts. For
         | language designers, purity is about the language itself, not
         | what you're doing in it. E.g. Haskell is still a pure language
         | even when you're reading and writing files. I don't think it's
         | as useful a definition than the lay definition of purity.
        
       | 752963e64 wrote:
        
       | quickthrower2 wrote:
       | The dirty secret is Typescript is going to become the most
       | popular language due to it's dirty pragmatism and simultaneously
       | very elegant features. It is definitely a get shit done language.
       | Typescript without JS toolchains (for example compiled to WASM
       | would make it very good).
        
       | vasergen wrote:
       | For me, the second variant with map chaining
       | const dataForTemplate = notificationData
       | .map(addReadableDate)         .map(sanitizeMessage)
       | .map(buildLinkToSender)         .map(buildLinkToSource)
       | .map(addIcon);
       | 
       | is the best one, it has way less mental overhead comparing with
       | the end result.
       | 
       | Also a catch with no error handling                 try {
       | return Just(JSON.parse(data));       } catch () {         return
       | Nothing();       }
       | 
       | in most cases is not the best idea, at least I'd put a log about
       | it
       | 
       | Nevertheless, waiting for the book from the author
       | 
       | UPD: edited code formatting
        
         | toastal wrote:
         | It's not performant though generally speaking you keep boxing
         | and unboxing the type (imagine having a list of 100,000
         | notifications and then mapping over it 5 times in a row). The
         | composition law would give you a just-as-readable option
         | const dataForTemplate = notificationData.map(pipe(
         | addReadableDate,           sanitizeMessage,
         | buildLinkToSender,           buildLinkToSource,
         | addIcon         ))
         | 
         | > in most cases is not the best idea, at least I'd put a log
         | about it
         | 
         | Well, in FP you don't want to do side effects like write to
         | console. Instead you want to hold onto the errors (with an
         | `data Either e a = Left e | Right a` instead of `data Maybe a =
         | Just a | Nothing`) til you get to the part of your application
         | where you _do_ do the side effects.                 try {
         | return Right(JSON.parse(data))       } catch (err) {
         | return Left(err)       }
        
       | thaway34453 wrote:
       | I do FP in JS, but I don't use Result or Option types or pipes
       | because they are not part of JS's lingua franca.
       | 
       | But I expect everyone in JS to be comfortable with
       | `Array.prototype.map`, `Array.prototype.reduce`, and closures as
       | these are core tenants of the language.
        
       | throwaway2037 wrote:
       | One take away from functional programming that I have
       | incorporated into my Java (and C#) code: If/When possible,
       | _never_ (ever ever!!!) re-assign a local variable. (Rare
       | exception: Classic C-style for-loop iteration with mutable `i`
       | integer variable.) Really, really, I am not trolling  / not a
       | joke. How / Why? How? All primative parameter value must be
       | final, e.g., `final iint level`, and local variables must always
       | be final. Why? Final vars are significantly easier to "reason
       | about" when reading code, as compared to non-final (mutable)
       | vars. If you are using containers, always, always, always use
       | immutable containers from Google Guava unless you have an
       | exceptionally good reason. Yes, the memory overhead will be
       | higher, but big enterprise corps do not care about adding 4/8/16
       | extra GB RAM to host your Java / C# app. Yes, I know that any
       | `Object` in Java is potentially mutable. As a work-around, try to
       | make all `Object`s immutable where possible. On the surface, the
       | whole thing / exercise feels like a terrible Computer Science
       | nitemare. In practice, it becomes trivial to convert code from
       | single-threaded to multi-threaded because most of your data
       | classes are already "truly" final.
        
         | quickthrower2 wrote:
         | I rarely reassign local variables too. (Other then the set to
         | null as a fallback then set again in a branch "pattern").
         | 
         | The only excuse is when I am doing something algorithmic and
         | that would improve the performance.
         | 
         | By extension I prefer local variables over class state and
         | static state and other "self managed lifetime" stuff like that.
         | 
         | And I am a GC blub programmer, I don't use Rust or C.
        
         | waynesonfire wrote:
         | > If/When possible, never (ever ever!!!) re-assign a local
         | variable.
         | 
         | Neat rule, but, it won't work. Firstly, as an example, Scala
         | which allows you to declare a read only val, you still see vars
         | used. There is no way you're going to get any traction
         | enforcing this across the developer spectrum.
         | 
         | The benefit of these concepts are realized when they are the
         | only option, hence FP and why mixed paradigm languages are
         | half-assed. Java isn't even a mixed-paradgim. You're wishing.
        
           | lmm wrote:
           | > Scala which allows you to declare a read only val, you
           | still see vars used.
           | 
           | You see them very rarely, and usually with a narrow scope.
           | 
           | I agree that you probably can't enforce an absolute rule of
           | no mutable variables. But making it the exception rather than
           | the rule (e.g. require it to be justified in code review)
           | makes a huge difference.
        
           | kaba0 wrote:
           | Local mutability is perfectly fine, and depending on the
           | algorithm can be much more readable.
           | 
           | Use the best tool for the job.
        
           | viscanti wrote:
           | > Neat rule, but, it won't work.
           | 
           | You'd get the benefit of easier to reason about code
           | everywhere you used it, even if others within the codebase
           | don't. Using that argument, we would argue that it's never
           | worth trying to find a cleaner way to implement something
           | because maybe some intern some day will do something weird in
           | a different part of the code base. We don't have to drop down
           | to the lowest common denominator for code quality and we
           | benefit every time we simplify things, even if not everyone
           | does.
        
         | senand wrote:
         | Agreed, I see this as a code smell. It's already hard from a
         | semantic point-of-view, normally you have then the same name
         | for two different meanings.
        
         | wtetzner wrote:
         | > If you are using containers, always, always, always use
         | immutable containers from Google Guava unless you have an
         | exceptionally good reason.
         | 
         | I actually prefer pcollections:
         | https://github.com/hrldcpr/pcollections
         | 
         | AtomicReference + immutable data types is a really nice way to
         | program in Java, and is basically the way most Clojure programs
         | are written.
        
           | acchow wrote:
           | Read the example about "producers" - If I chain a whole bunch
           | of producing together across many different Pcollections, I'm
           | essentially forming a graph behind the scenes? Since no
           | copying is happening
           | 
           | Surely this would cause some strange performance outcomes
           | with, say, a gradually built up immutable list.
        
         | P_I_Staker wrote:
         | That's interesting. On the other hand, I've seen code go
         | through great lengths to not do a double assign.
         | 
         | I doubt it was easier to reason about at all. The code set an
         | error var on a number of if / else conditions. They then used a
         | separate flag, so that a double write wouldn't be necessary.
         | ie. int flag = 0;
         | 
         | int err; // notice no initializer
         | 
         | if(stuff) { flag = 1; err = 1; } else {}
         | 
         | if(other_stuff) { flag = 1; err = 2; } else {}
         | 
         | if(flag) { LogError(err); }
         | 
         | I follow the "avoid double write" convention too, but in some
         | cases, it can become very difficult to reason whether a local
         | is uninitialized; this is a pretty terrible class of bug,
         | because you work with garbage data off of the stack.
         | 
         | Setting to zero at declaration makes it much clearer that it
         | will never be uninitialized, but it's essentially meaningless
         | and arguably a form of dead code.
         | 
         | Maybe someone will suggest a redesign? More functions, smaller
         | functions? It seems that there's a strong (though unpopular)
         | argument that you should use medium sized functions, and some
         | teams insist on doing this. In some cases, it can be easier to
         | find the content, verify specifications.
         | 
         | Edit: On second thought I can see we didn't avoid the double
         | write, just did it in a different variable. So I don't
         | understand what the author's point is, lol.
        
           | bluefirebrand wrote:
           | When I have a flag that is bouncing through a bunch of
           | conditionals only to return at the end, I prefer to change it
           | to multiple return paths instead of multiple spots to modify
           | the flag that is being returned.
           | 
           | If you are doing a lot of work inside those branches it may
           | be worth a refactor to simplify the branching logic.
        
         | rzzzt wrote:
         | Java 11+ has factory methods for unmodifiable collections:
         | https://docs.oracle.com/en/java/javase/11/docs/api/java.base...
        
         | hinkley wrote:
         | There's a short list of reasons to factor out a method. The
         | most popular one is "if you see the need for inline comments
         | for a block of code, maybe the code shouldn't be inline", but
         | feeling the need to redefine a variable, especially in the
         | middle of a function, is often a good indicator of a new scope
         | starting. Sending variable foo with an increment, a merge, or a
         | concatenation to another function is fairly readable. Having
         | foo and foo' inline is quite a bit harder on working memory.
        
       | bob1029 wrote:
       | FP is only part of the equation when working with meaningfully-
       | complex systems. Having a clear data + relational model is the
       | other big part.
       | 
       | I would strongly recommend reviewing the functional-relational
       | programming model described in this paper -
       | http://curtclifton.net/papers/MoseleyMarks06a.pdf
       | 
       | The overall theme goes something like: FP is for handling all
       | your logic, and RP is for arranging all of your data. Some sort
       | of relational programming model is the only way to practically
       | represent a domain with high dimensionality.
       | 
       | For real-world applications, we asked ourselves: "Which
       | programming paradigm already exhibits attributes of both FP and
       | RP?" The most obvious answer we arrived at is SQL. Today, we use
       | SQL as a FRP language for configuring our product. 100% of the
       | domain logic is defined as SQL queries. 100% of the domain data
       | lives in the database. The database is scoped per unit of
       | work/session, so there are strong guarantees of determinism
       | throughout.
       | 
       | Writing domain logic in SQL is paradise. Our tables are
       | intentionally kept small, so we never have to worry about
       | performance & indexing. CTEs and such are encouraged to make
       | queries as human-friendly as possible. Some of our most
       | incredibly complex procedural code areas were replaced with not
       | even 500 characters worth of SQL text that a domain expert can
       | directly understand.
        
         | UK-Al05 wrote:
         | Nearly every system I worked on that had significant business
         | logic in SQL turned out to be a maintenance nightmare. Used to
         | be a lot of this in the 90s or early 2000s. Where dB venders
         | encouraged it for obvious reasons.
         | 
         | SQL isn't built with sensible decisions. Delete/update forget a
         | where clause? Whoops. Lots of traps like that. Also it's not
         | easily testable. Domain concepts don't always easily map.
        
           | alexvoda wrote:
           | Part of the reason is that SQL is simply a bad language (the
           | JavaScript of databases).
           | 
           | Part of the reason is also the thinking and philosophy behind
           | DBMSs as interactive systems. Especially with regards to
           | code.
           | 
           | A function doesn't just exist. You create a function and it
           | lives in the database until you alter it or drop it.
           | 
           | This creates a different (temporal?) impedance mismatch with
           | standard code management tools like version control. The
           | result is most often a maintenance nightmare.
        
           | primeblue wrote:
        
         | eddsh1994 wrote:
         | Oh god, no! Please no!
         | 
         | Okay maybe it works for you, but I've worked on one of these
         | systems for a financial engine with over 10m SQL LoC. This was
         | a big product that was ~15 years old and used by dozens of
         | companies having bespoke feature flags that changed significant
         | parts of the calculation engine. Everyone except a couple grey
         | beards who'd joined straight out of university left that place
         | after a few years because of how insane it was to work on and
         | we all became way too interested in good architecture design
         | from that experience. My friends from that time who I still
         | keep in touch with are almost entirely working on FP-based
         | environments now.
        
           | alexvoda wrote:
           | When done poorly that is the result. And it is very easy to
           | do poorly.
           | 
           | But I think the basic premise of combining functional and
           | relational is valid. At the very least it avoids the object
           | relational impedance mismatch.
        
         | alexvoda wrote:
         | A few points:
         | 
         | - I can understand why this might appear as hell to many. SQL
         | is unwieldy and doesn't play nice with many tools we use to
         | make life easier.
         | 
         | - I agree with the fundamental premise that a combination of
         | functional and relational principles can be highly effective
         | for data heavy scenarios
         | 
         | - i disagree that pure SQL is the solution to achieve this. If
         | using MS SQL Server, there are great opportunities to leavrage
         | the CLR and F# (with caveats because F# gets less love than
         | C#). You can write functional logic once and use it both
         | outside of the database and inside the database. PostgreSQL has
         | extensions for other languages.
        
         | wibblewobble124 wrote:
         | SQL is not functional. But otherwise I support the desire for
         | an FP and relational language.
        
           | bob1029 wrote:
           | > SQL is not functional
           | 
           | I agree that you are technically correct. It is simply
           | declarative in nature. I've got a habit of conflating these
           | terms. Functions aren't first-class citizens in SQL. We also
           | have some UDFs that are impure (because the real world
           | unfortunately exists).
           | 
           | I'd be perfectly happy to rename this a "Declarative-
           | Relational" programming model if that sits better with
           | everyone.
        
       | oxfordmale wrote:
       | The first code iteration in this article could have been deployed
       | to Production before I finished reading the rest of the article.
       | 
       | Functional programming definitely has its use cases, as side
       | effects can introduce bugs. Unfortunately real world business
       | logics often does require side effects. Often you only find out
       | about side effects later in a project, and then you suddenly need
       | to start hacking your clean functional approach.
        
         | z9znz wrote:
         | > real world business logics often does require side effects
         | 
         | Yeah, all business logic requires side effects, else it is
         | doing nothing :).
         | 
         | But following some FP practices, you can push the side effects
         | very far out to ward the edges. Instead of typical OOP, where
         | objects get passed around and mutated anywhere and everywhere
         | (which makes identifying where certain things started to go
         | wrong), with pure, single responsibility functions you can
         | write very simple but thorough tests which give you vastly more
         | confidence about the code. And as a huge added benefit, the
         | lines of test code actually go down because there's so much
         | less setup and teardown (mocking, stubbing, etc.).
        
         | mrkeen wrote:
         | > side effects can introduce bugs
         | 
         | > real world business logics often does require side effects
         | 
         | > you suddenly need to start hacking your clean functional
         | approach
         | 
         | These are great arguments as to why you need:
         | 
         | a) A type system which tracks effects
         | 
         | b) A language which makes refactoring safe and easy
        
       | lexx wrote:
       | Beautiful website. The transitions between the code blocks are a
       | very nice touch
        
       | steinuil wrote:
       | I'm a fan of functional programming but I'm pretty sure this post
       | would do a terrible job of convincing anyone to try FP out.
       | There's a very bad pattern of replicating very specific language
       | features and control flow structures just to make them more
       | similar to point-free Haskell, which is not going to win anybody
       | over.
       | 
       | The author begins by replacing a language feature, the .
       | operator, with a pipe() function. After that they swap out
       | exceptions for Result, null/undefined for Maybe, Promise with
       | Task, and the final code ends up becoming an obfuscated mess of
       | wrapper functions and custom control flow for what you could
       | write as:                   fetch(urlForData)
       | .then(data => data.json())           .then((notifications) =>
       | notifications.map((notification) => ({
       | ...notification,               readableDate: new
       | Date(notification.date * 1000).toGMTString(),
       | message: notification.message.replace(/</g, '&lt;'),
       | sender: `https://example.com/users/${notification.username}`,
       | source: `https://example.com/${notification.sourceType}/${notific
       | ation.sourceId}`,               icon: `https://example.com/assets
       | /icons/${notification.sourceType}-small.svg`,             })
       | )           .catch((err) => { console.log(err); return fallback
       | });
       | 
       | ...which is just as functional because doesn't involve any
       | mutation and it doesn't require several pages of wrapper
       | functions to set up, you can tell what it does at a glance
       | without having to look up any other pieces of code, it's gonna
       | run faster, and it uses standard control flow which you can
       | easily debug it using the tools you use for any other JS code.
       | 
       | This post has nothing to do with functional programming, this is
       | a poor monad tutorial.
        
         | Kerrick wrote:
         | Your response describes exactly how I felt using RxJS for the
         | first time.
        
           | azangru wrote:
           | I just wanted to say, among all the negativity in the
           | comments, that I love RxJS, and fell in love with it after
           | Jafar's workshop.
           | 
           | As Ben Lesh often says, there are sadly a lot of
           | misconceptions around Rxjs and the Observable type. The
           | Observable type is a primitive so useful that it keeps
           | getting reinvented over and over (React's useEffect is a
           | weird React-only observable; a redux store is an observable);
           | whereas Rx is a set of convenience functions to help with the
           | use of the Observable type. If people are happy to use
           | lodash, I can't understand what makes them so unhappy about
           | Rx, which is like lodash, but for async collections.
        
           | dmitriid wrote:
           | It took the author of RxJava _months_ to understand the
           | concept. Screenshot from the book:
           | https://twitter.com/dmitriid/status/811561007504093184
           | 
           | (Jafar is the author of Rx .Net, and even he couldn't explain
           | it to the future author of RxJava :) )
        
           | dtech wrote:
           | I've been working with Rx for 10 years or so and I think it's
           | a terrible model.
           | 
           | If you _need_ processing of streams of asynchronous dynamic (
           | "hot") data it's the least-bad model I know, otherwise there
           | are much better ways, especially now that many languages have
           | async-await keywords or at least a Future/Promise type.
        
             | halpmeh wrote:
        
           | antihero wrote:
           | I found using rxjs with redux to be a way of decoupling
           | control flow. Instead of having a function with a bunch of
           | thunks, you did something and then other bits of code to
           | could effectively subscribe to the side effects of that and
           | you built your control flow up that way. It had pros and
           | cons, was quite powerful but you ended up with a lot of
           | indirection and not exactly knowing what was going to happen.
        
           | Cthulhu_ wrote:
           | I've only been using RxJs for a short while now (we're moving
           | to react soon), I don't really get it. I mean I get it, just
           | not why we're using it just to consume some REST APIs. 80-90%
           | of that is boilerplate code to please RxJs, and only alll the
           | way down through two layers of stores / states and a library
           | another team maintains is there a single call to `fetch()`
           | that does the actual work.
           | 
           | I'm pushing to use react-query with the new app, I think
           | people will get confused when it turns out hooking up the
           | whole API will take hours.
        
         | briznad wrote:
         | I read halfway through the article before my eyes glazed over
         | and I could no longer tell whether the post was serious or a
         | joke.
        
         | nailer wrote:
         | Or post ES2017, without all the .then()s:                 const
         | doThing = async (url, fallback) => {         try {
         | const response = await fetch(url)           const notifications
         | = await response.json()           return
         | notifications.map((notification) => ({
         | ...notification,             readableDate: new
         | Date(notification.date * SECONDS).toGMTString(),
         | message: notification.message.replace(/</g, '&lt;'),
         | sender: `https://example.com/users/${notification.username}`,
         | source: `https://example.com/${notification.sourceType}/${notif
         | ication.sourceId}`,             icon: `https://example.com/asse
         | ts/icons/${notification.sourceType}-small.svg`,           }))
         | } catch (error) {           console.log(error.message);
         | return fallback         }       }
        
           | adamwk wrote:
           | And now we've gone full circle to writing imperative code
        
             | nailer wrote:
             | That's a pure function, asides from the HTTP call (which it
             | would seem reasonable to mock). Is there a better way to
             | handle it?
        
               | adamwk wrote:
               | I'm not disparaging it; I think it's great that languages
               | have new constructs making certain FP patterns obsolete
        
           | still_grokking wrote:
           | Is this code really equivalent?
           | 
           | Wouldn't it block on the `await` calls, whereas the original
           | code would instantly pass control back to the caller?
           | 
           | (Sorry if this question is odd. My JS is a little bit
           | rusted).
        
             | LegionMammal978 wrote:
             | It's an async arrow function, which means that it returns a
             | `Promise` when called, much like the original code that
             | constructs a `Promise` explicitly. This `Promise` resolves
             | once the function returns.
        
               | still_grokking wrote:
               | Thanks for the prompt answer!
               | 
               | I've overlooked the `async` on the first line... My
               | fault. :-|
        
             | 0x445442 wrote:
             | I'm JS illiterate but I think control is returned to the
             | main thread until the await call returns, at which time the
             | execution continues.
        
               | still_grokking wrote:
               | JS is single threaded.
               | 
               | Async / await is just a code transformation that
               | introduces Promise wrappers.
               | 
               | The code should be equivalent to the original. (I've just
               | overlooked the top-level `async`...).
        
         | borbulon wrote:
         | > ends up becoming an obfuscated mess of wrapper functions and
         | custom control flow
         | 
         | This right here is the reason I don't like pure functional
         | programming. Any engineer should be able to pick up your code
         | and understand it pretty close to immediately. And with pure
         | FP, even when they understand functional programming, they end
         | up wasting valuable time tracking down what it is you're trying
         | to do.
         | 
         | * I guess I need to edit to say I mean pure FP in a language
         | not explicitly built for pure FP. The article is about
         | implementing in JS, this is what I'm addressing.
        
           | steinuil wrote:
           | I have to agree with you as far as pure functional
           | programming goes. I also don't like the Haskell approach of
           | of overgeneralizing concepts just because you can; it's the
           | FP equivalent of stuffing every design pattern you can into
           | your OO code. I'd argue that not every pure functional
           | programming language _has_ to be like that but I 'm pretty
           | sure all the ones that exist are.
        
             | valenterry wrote:
             | Please don't mix the two things. There are a lot of
             | abstractions in Haskell (monads, monoids, ...) but those
             | are 100% orthogonal to pure functional programming. You can
             | do the latter without any of those abstractions even
             | existing in the language.
             | 
             | And if you want to see an example for a language that is
             | not like that, look at Scala and ZIO (www.zio.dev). It is a
             | library for pure functional programming, but look at the
             | examples - those abstractions you mention are not there.
             | The library really aims at making concurrent/async
             | programming easier by leveraging pure functional
             | programming but without crazy category theory stuff.
        
               | HelloNurse wrote:
               | Two other things that shouldn't be mixed are a
               | programming language's features and what programmers are
               | using them for. As noted in other comments, Haskell is
               | good at defining all sorts of functions, but the card
               | castles of excessive and inappropriate algebraic
               | abstraction are a tradition of rather uniformly extremist
               | Haskell users.
        
               | jose_zap wrote:
               | I took a look at ZIO
               | (https://zio.dev/guides/quickstarts/hello-world) and just
               | the first example explains a monad.
               | 
               | That first example shows that the for syntax desugars to
               | nested flatMap. Which is analogous to Haskell's do
               | notation, which desugars to nested bind.
               | 
               | The abstractions you said are not there, seem to actually
               | be there in zio!
        
               | valenterry wrote:
               | > the first example explains a monad
               | 
               | Strictly speaking that's wrong. Yes, ZIO is a monadic
               | type. But you really don't need to understand monads to
               | understand the example. In fact, the word monad does not
               | even appear at all. Or would you say javascript also
               | "explains a monad" when someone explains how to
               | map/flatmap over an array? I doubt it.
               | 
               | > That first example shows that the for syntax desugars
               | to nested flatMap. Which is analogous to Haskell's do
               | notation, which desugars to nested bind.
               | 
               | > The abstractions you said are not there, seem to
               | actually be there in zio!
               | 
               | Again, those concepts are even in javascript. In fact,
               | they are in every language. The question is if it is
               | decided to make them explicit and reusable or not. And
               | ZIO chose to not require any knowledge of them to be able
               | to use the library - and that's what we are talking about
               | here no?
               | 
               | Let's look at the code of flatMap that you are
               | complaining about:                 /**        * Returns
               | an effect that models the execution of this effect,
               | followed by the        * passing of its value to the
               | specified continuation function `k`, followed        * by
               | the effect that it returns.        *        * {{{
               | * val parsed = readFile("foo.txt").flatMap(file =>
               | parseFile(file))        * }}}        */       def
               | flatMap[R1 <: R, E1 >: E, B](k: A => ZIO[R1, E1,
               | B])(implicit trace: Trace): ZIO[R1, E1, B] =
               | ZIO.OnSuccess(trace, self, k)
               | 
               | Where are monads, monoids, functors, ... here? They are
               | not to be found. Replace "flatMap" with "then" and you
               | pretty much have javascript's promises.
        
               | jose_zap wrote:
               | What I meant to say is that the abstractions are
               | definitely there in zio, which was meant to address your
               | first comment where you said that zio did not have them.
               | 
               | By reading the docs I could easily recognize monads. If
               | you replace "for" with "do", they even have the same
               | syntax! I could also see clear examples of things that
               | were modeled as monoids and functors. I would claim that
               | zio took inspiration from Haskell to model the composable
               | parts.
               | 
               | Hey, I'm not complaining about any code, and specially
               | not flatMap. I think it is a great design. It is the bind
               | operator in the monad class in Haskell, and there is also
               | syntax sugar to hide it and make it look like imperative
               | code, just like Haskell. I like that!
               | 
               | It seems to me that it is fair to say that the
               | abstractions are useful as you recognize in your previous
               | comment. Maybe you just have an aversion against the
               | abstraction names, or the way many Haskell-related
               | articles go on and explain them... which is fair enough.
               | 
               | I learned Haskell without having to understand those
               | concepts. I could just used them by experimenting with
               | what was possible and seeing examples from other people.
               | It was not particularly difficult. So, as you also
               | figured out with zio, understanding the abstractions is
               | not a requirement for using them.
        
               | steinuil wrote:
               | I did acknowledge that they are orthogonal when I said
               | that not every pure FP language has to be like that.
               | Thanks for pointing out ZIO, I didn't know about it.
        
               | valenterry wrote:
               | I know, but you also said "but I'm pretty sure all the
               | ones that exist" so I wanted to show you a counter-
               | example. I'm also not surprised by your thought, since
               | you are right - most of the time it gets mixed, which is
               | actually sad.
               | 
               | We need more practical pure functional programming
               | libraries that focus on tackling problems with concurrent
               | updates, streaming, state-changes etc. without forcing
               | you to take a course in category theory beforehand.
        
           | valenterry wrote:
           | > Any engineer should be able to pick up your code and
           | understand it pretty close to immediately.
           | 
           | So a webdev should almost immediately pick up a mix of C++
           | and assembly?
           | 
           | No. There's a reason we specialize. That is not a good
           | argument against functional programming.
        
             | borbulon wrote:
             | You're hitting a strawman here. I shouldn't have to
             | explicitly say that I meant someone with at least some
             | experience in the language you happen to be writing in.
        
               | valenterry wrote:
               | Okay, I think your edit made it more clear. I would also
               | not try to turn a javascript codebase into pure
               | functional style. On that one I agree with you. :)
        
               | Verdex wrote:
               | I'm not convinced that previous poster was hitting a
               | strawman.
               | 
               | Your argument (if I understand correctly) is that given
               | some language (here javascript) that one ought not
               | program in such a way that other people who use that
               | language are incapable of understanding it. This example
               | of FP involves a bunch of junk that makes javascript
               | incomprehensible to javascriptors therefore it's bad.
               | 
               | Now, previous poster replies with "Hey not everyone
               | understands c++ and assembly ..." and this does sort of
               | sound like a strawman, however we can extract the core
               | argument as "there exist things which you haven't seen
               | before which you don't understand, but that doesn't make
               | them bad" and that does not sound like a strawman. That
               | sounds like a legit argument.
               | 
               | For example, perhaps there exists a library which
               | performs some domain specific task using FFT, linear
               | algebra, and distributed computing load balancer
               | algorithms. All of it in javascript. An arbitrary
               | javascript developer is probably not going to be able to
               | understand what's going on. However, that wouldn't be a
               | legit argument against FFT, linear algebra, or
               | distributed computing load balancing algorithms.
               | 
               | Specializations exist. Pure FP in javascript might not be
               | a great idea, but it possibly confusing someone who
               | otherwise knows javascript doesn't feel like a real
               | argument against it to me.
        
               | 0x445442 wrote:
               | But is the article/book actually advocating the idea that
               | this non-idiomatic paradigm should only be used in very
               | specific places in a code base where it's objectively and
               | demonstratably better? Or is the article/book advocating
               | wide spread usage? I think it's the latter and so I think
               | the comment was a straw man.
               | 
               | As an aside I think this a problem with kitchen sink
               | languages that allow all these different paradigms. Maybe
               | not so much with JavaScript because its roots are more
               | functional but with Java where they've continually bolted
               | on functional capabilities. With a language like
               | Smalltalk, there is no idiomatic Smalltalk, just
               | Smalltalk. I imagine something like Clojure is the same
               | way. With these kitchen sink languages you can end up
               | with code bases that vary wildly in style, especially if
               | there's been a lot of turnover in the project.
        
               | Verdex wrote:
               | With respect to your first point:
               | 
               | Wide spread usage is a relative term. Like, if the a
               | program just happens to be 99% FFT code, then you'll have
               | "wide spread usage" of incomprehensible FFT code in the
               | code base. This is a question of scope of the project. So
               | I don't think that an argument becomes strawman just
               | because most projects will probably be bigger than their
               | specialized component.
               | 
               | With respect to your second point:
               | 
               | Hard agree. I think languages should have much more
               | constrained focus that largely disallows an impedance
               | mismatch between what you're trying to do and how you go
               | about doing it.
               | 
               | [Worth noting is that I largely agree with the points
               | against this type of FP in javascript. However, I'm
               | opposed to the line of reasoning that's being used
               | against it. Something not being readily understood is not
               | a good argument for rejection. Because anything worth
               | doing that hasn't already been done is likely to be
               | incomprehensible until you've spent some time with it.]
        
             | jjav wrote:
             | > > Any engineer should be able to pick up your code and
             | understand it pretty close to immediately.
             | 
             | > So a webdev should almost immediately pick up a mix of
             | C++ and assembly?
             | 
             | There's a reason assembly has been relegated to very
             | specific & specialized use cases. I'd almost want to say
             | the same about C++.
             | 
             | The best production code is very simple, very
             | understandable.
        
           | jerf wrote:
           | There's a difference between "pure FP in an imperative-
           | oriented language" and "pure FP in a pure-FP-oriented
           | language". In Haskell, this isn't an obfuscated mess of
           | wrapper functions and custom control flow, it's the most
           | straightforward and sensible way to do things. Functions have
           | very thin syntax and don't get in the way, laziness means you
           | lose all the function wrappers that imperative languages add
           | just for that, etc.
           | 
           | Personally I find trying to write Haskell in an imperative
           | language to make exactly as much sense as trying to write
           | imperative code in Haskell. Same error, same reasons, same
           | outcome.
        
             | agentultra wrote:
             | Hot take here: Haskell is also a better imperative
             | language.
        
               | still_grokking wrote:
               | For context:
               | 
               | https://stackoverflow.com/questions/6622524/why-is-
               | haskell-s...
        
               | throwaway17_17 wrote:
               | Bob Harper, from CMU, has a really fun section of his
               | 2021 OPLSS lectures where he talks about Haskell being
               | the best version of Modernized Algol, so your hot take
               | has, at least, some measure of reasoned support for
               | precedent. However, the syntax for imperative programming
               | in Haskell is not quite as simple as it could be and so
               | makes it a tough fit for a 'better' imperative language.
        
             | borbulon wrote:
             | I agree completely, but since the article is about writing
             | JS in a pure FP manner, I was addressing that and not
             | anything else.
        
               | jerf wrote:
               | That's fine. I just couldn't tell. I agree with you.
        
             | PaulHoule wrote:
             | There's also a difference between a Scottsman and a "True
             | Scottsman".
             | 
             | There is a common story of a programmer who has journeyed
             | like an itinerant martial artist looking for functional
             | programming enlightenment but never finds it... Our
             | industry is way too susceptible to snake oil stories like
             | "If I wrote all my tests first my programs would never have
             | any bugs" or "If I wrote my programs in Erlang they
             | wouldn't have any bugs..."
             | 
             | There are certain tasks for which functional programming
             | idioms are highly effective, other ones where you will
             | twist your brain into knots and end up writing completely
             | unmaintainable code.
        
               | jerf wrote:
               | This is absolutely not a "true scotsman" argument. I am
               | talking about very distinct classifications of languages,
               | with _wildly_ divergent feature sets, runtimes,
               | libraries, and communities. The differences are real and
               | objective.
               | 
               | This is just a special case of the more general
               | principle, "Don't write X in Y". Don't write BASIC in C.
               | Don't write C in Python. Don't write FP in imperative.
               | Don't write imperative in FP. Don't think you've solved
               | whatever problems you have with Y when you're forced to
               | use it by writing X in Y. Writing X in Y inevitably leads
               | to the _worst_ of both worlds, not the best.
        
               | PaulHoule wrote:
               | There is a triangle of promise, hype and results. When
               | the promise is there and the hype is there but the
               | results aren't there that's different from promise
               | without hype. Haskell has a lot of promise and a lot of
               | hype and could use some "tough love" in terms of
               | understanding why it hasn't been adopted in industry.
               | (Hint: most of the time when somebody is writing a
               | program that whole point is that they want to create a
               | side effect. A real revolution in software might come out
               | of that insight.)
               | 
               | "X in Y" is a common programming motif in advanced
               | systems. Large systems in C, for instance, tend to
               | contain some kind of runtime and DSL-ization if not an
               | embedded interpreter. I think it's an absolute blast to
               | write DSLs in Java and unlike other languages that get
               | DSL hype (Scala) you have IDEs that work and cooperate
               | with this use case.
        
         | still_grokking wrote:
         | FP is the best thing since sliced bread, don't get me wrong!
         | 
         | But the seemingly arising "Haskell religion" is at least as
         | mislead as the OOP-religion that held mainstream in
         | stranglehold for a long time.
         | 
         | Haskell's syntax isn't anything to imitate. It's hostile to IDE
         | features, at least. Alone that should make it a no-go.
         | 
         | The next thing is that Haskell's features may make sense in the
         | Haskell context, but they don't make any sense at all in almost
         | any other language.
         | 
         | When you don't have strong types, no lazy evaluation by
         | default, and it's not mandatory to use IO-wrappers, it makes
         | not sense to mimic solutions that arose out necessities that
         | are again results of constrains of Haskell's feature design.
         | You need to do some things in Haskell the Haskell way because
         | Haskell is the way it is. In a different language the chosen
         | solutions are at best bonkers (even they may make sense for
         | Haskell).
         | 
         | As always: It's a terrible idea to start doing something
         | because "it's cool" and the "new hot shit", without actually
         | understanding _why exactly_ things are (or should be) done the
         | way they are. The  "Haskell religion" is by now imho already
         | mostly only cargo cult... The more worrisome part is that it
         | seems it attracts more and more acolytes. This will end up
         | badly. It will likely kill the good ideas behind FP and only
         | leave a hull of religious customs that the cult followers will
         | insist on; exactly like it happened to OOP in the past.
         | 
         | That's my personal opinion, speaking as a big FP Scala fan.
        
           | tikhonj wrote:
           | JavaScript et al do have IO wrappers, they just call them
           | promises and only force _some_ effects through them.
        
             | still_grokking wrote:
             | The key word here was "mandatory usage".
             | 
             | BTW: Haskell uses its IO wrapper also only for a very
             | narrow set of effects.
             | 
             | One of my favorite examples: `head []` will result in a
             | crash at runtime. IO won't safe you. (Besides that the
             | whole "effect wrapping" story in Haskell is anyway shallow
             | at best. There is nothing like "none observable effects" at
             | all as every computation needs to happen in space-time,
             | leaving observable traces therein; you can't define away
             | "side channels" and call the result "pure"; that's mocking
             | reality).
        
               | cies wrote:
               | > One of my favorite examples: `head []`
               | 
               | This is realllly unidiomatic in real world Haskell. Even
               | removed from Elm and PureScript.
               | 
               | Idris maybe has better effect handling for your taste.
               | Also see: Koka, Frank (mainly a paper)
        
               | still_grokking wrote:
               | > This is realllly unidiomatic in real world Haskell.
               | 
               | Whether idiomatic or not does not matter. It proves my
               | point:
               | 
               | IO won't save you, and even very mundane effects are not
               | part of the game...
               | 
               | Idris is the "better Haskell" sure, but the effect
               | tracking is still part of the uncanny valley (still IO
               | monad based).
               | 
               | Koka is a toy, and Frank mostly "only a paper" (even
               | there is some code out there).
               | 
               | The "Frank concept" is to some degree implemented in the
               | Unison language, though:
               | 
               | https://www.unison-lang.org/learn/fundamentals/abilities/
               | 
               | Having a notion of co-effects (or however you please to
               | call them) is imho actually much more important than
               | talking about effects (as effects are in fact neither
               | values nor types--something that all the IO kludges get
               | wrong).
               | 
               | I think the first practicable approach in the mainstream
               | about this topic will be what gets researched and
               | developed for Scala. The main take away is that you need
               | to look at things form the co-effects side first and
               | foremost!
               | 
               | In case anybody is interested in what happens in Scala
               | land in this regard:
               | 
               | https://www.slideshare.net/slideshow/embed_code/key/aLE9M
               | 37d...
               | 
               | https://docs.scala-
               | lang.org/scala3/reference/experimental/cc...
               | 
               | But also the development in OCaml seems interesting:
               | 
               | https://github.com/ocaml-multicore/eio#design-note-
               | capabilit...
               | 
               | Look mom, "effects", but without the monad headache!
        
               | gottlobflegel wrote:
               | > This is realllly unidiomatic in real world Haskell.
               | 
               | Yet it is the actual behaviour in the stdlib Prelude.
        
               | 1-more wrote:
               | Yep. I think it is needed to satisfy some category theory
               | thing but I never got a good answer on that. I like to
               | use nri-prelude since I went from Elm to Haskell and it
               | has the same idioms, to wit `head : List a -> Maybe a`.
        
           | misja111 wrote:
           | > But the seemingly arising "Haskell religion" is at least as
           | mislead as the OOP-religion that held mainstream in
           | stranglehold for a long time.
           | 
           | I wanted to say the same but you were faster than me. The
           | article reminded me a lot of the design patterns fad in the
           | OOP world: that compulsion to make everything abstract and
           | reusable even if there's no use for it yet. But hey, at some
           | point it might be needed and then it would be great!
           | 
           | Of course there are some cases where you really want to be
           | ahead of what might come , e.g. public library api's, but
           | those are rare.
        
             | celeritascelery wrote:
             | I have heard is said that both OOP and functional design
             | are best applied only about 80% of the time. More than that
             | and you are overfitting the method to things where it
             | applies poorly.
        
               | pencilguin wrote:
               | Every big enough system has a few parts that would fit
               | OOP, and a few parts that would fit FP. If your language
               | supports those, then great, use those for them.
               | 
               | The overwhelming majority of problems do not fit OO, and
               | using OOP on them makes a mess. Similarly, FP.
        
           | efnx wrote:
           | I think a lot of this (to quote the Dude) "is just like, your
           | opinion, man".
           | 
           | Haskell is great but it's not for everybody. It really gets
           | you thinking about software engineering in a different way.
           | 
           | I wrote Haskell full time for five years, with some of the
           | best in the industry and I can tell you that there is no real
           | religion. I will admit the language attracts ideologists,
           | theorists and folks who like to pioneer (which I like), but
           | everybody is just trying to make things work - these are
           | patterns that solve problems and guidelines that avoid
           | problems.
           | 
           | Now, it's really hard to take the good parts of Haskell and
           | bring them to a language like JavaScript and have it feel
           | "natural" - especially to someone who isn't a native Haskell
           | writer! And especially a concept as reliant on higher kinded
           | types as effects!
        
           | chongli wrote:
           | _Haskell 's syntax isn't anything to imitate. It's hostile to
           | IDE features, at least._
           | 
           | Can you elaborate on this? I haven't used Haskell in years
           | but I recall enjoying some of its really cool IDE-friendly
           | features, such as typed holes and the ability to press a key
           | and have whatever is under my editor's cursor show me its
           | type and another key to insert that inferred type into the
           | document.
           | 
           | I have heard that more recent versions support nice record
           | syntax using the '.' operator (but without whitespace, to
           | differentiate it from composition). That's also very IDE
           | friendly since type inference in the editor should be able to
           | resolve the members of a data type that's been defined with
           | record syntax.
        
             | still_grokking wrote:
             | The main problem is discovery.
             | 
             | When I hold some object I can easily discover the things I
             | can do with that object--just by typing "." after the
             | object reference.
             | 
             | In something like Haskell I need to know _upfront_ what I
             | may do with some  "object". The IDE can't help me discover
             | the methods I need. All it can do is to show me _all_
             | available functions in scope. Most of this functions aren
             | 't what I'm looking for. But the IDE can't know that as
             | it's missing the "context" in which I want to call my
             | functions / methods.
             | 
             | And regarding records in Haskell: First of all you will get
             | beaten when you use them (that's part of the religious
             | movement and has nothing to do with comprehensible
             | reasons). The other part is: Records are no substitute for
             | objects. Not even close. Those are just quite primitive
             | structs. (To learn how unpractical is it to try to build
             | objects from structs without proper language support just
             | ask someone who was forced to use C after coming from a
             | more complete OO language).
        
               | TremendousJudge wrote:
               | to quote grugbrain.dev:
               | 
               | >grug very like type systems make programming easier. for
               | grug, type systems most value when grug hit dot on
               | keyboard and list of things grug can do pop up magic.
               | this 90% of value of type system or more to grug
               | 
               | >big brain type system shaman often say type correctness
               | main point type system, but grug note some big brain type
               | system shaman not often ship code. grug suppose code
               | never shipped is correct, in some sense, but not really
               | what grug mean when say correct
               | 
               | >grug say tool magic pop up of what can do and complete
               | of code major most benefit of type system, correctness
               | also good but not so nearly so much
        
               | CharlieDigital wrote:
               | Haha, I love this.
               | 
               | I wrote up something similar [0] but not quite as
               | creative. _Discoverability_ and _Locus of Control_ are
               | two of the best reasons to use OOP that rarely comes up
               | in the academic discussion of OOP as a practice.
               | 
               | Honestly, OOP is many cases is simply more practical.
               | 
               | Even imperative code has its merits; case in point: it's
               | often much easier to debug.
               | 
               | [0] https://medium.com/@chrlschn/weve-been-teaching-
               | object-orien...
        
               | still_grokking wrote:
               | > https://grugbrain.dev/
               | 
               | How could I miss that?
               | 
               | Gold! Thanks!
        
               | skhm wrote:
               | >but grug must to grug be true, and "no" is magic grug
               | word. Hard say at first, especially if you nice grug and
               | don't like disappoint people (many such grugs!) but
               | easier over time even though shiney rock pile not as high
               | as might otherwise be
               | 
               | >is ok: how many shiney rock grug really need anyway?
               | 
               | ... I actually needed to see this today
        
               | zopa wrote:
               | > In something like Haskell I need to know upfront what I
               | may do with some "object". The IDE can't help me discover
               | the methods I need. All it can do is to show me all
               | available functions in scope.
               | 
               | Sorry, but this just isn't true. Hoogle
               | <https://hoogle.haskell.org/> searches function by type,
               | fuzzily: ask for functions whose first parameter is the
               | type of the object-like thing, and you'll get just what
               | you're looking for. And it's perfectly possible to run
               | hoogle locally and integrate it with your editor.
               | 
               | Now, the tooling for a language like Java have had
               | several centuries more of aggregate development work done
               | on them compared to Haskell's tools, and if that polish
               | is a difference-maker for you, that's fine! But it's not
               | a fundamental limitation, and claiming it is is just fud.
        
               | lolinder wrote:
               | The main point is that the noun-first syntax of OO
               | languages means that by just _starting_ to write the code
               | that you know you need, you 've already given the IDE
               | enough information to give you a list of options for
               | which function to use. That kind of tight integration
               | directly into the editor is hard with Haskell because you
               | have to write out the function name first.
               | 
               | I could imagine an editor having some sort of "holes"
               | capability, where I can hit a key combo to insert a hole
               | where a function should go, provide the function
               | arguments, then double back and fill in the hole with
               | search results from Hoogle. Done right, such a system
               | would be marginally harder to use than Java-style IDE
               | completions, but not enough to be a problem. The main
               | difficulty is that the implementation and UX complexity
               | of such a system is _far_ greater than with a noun-first
               | syntax.
        
               | tome wrote:
               | > That kind of tight integration directly into the editor
               | is hard with Haskell because you have to write out the
               | function name first.
               | 
               | Sort of. But you can just write                   _ x
               | ^
               | 
               | and get the same sort of benefit as you get from
               | x.           ^
        
               | zopa wrote:
               | The approach you're describing sounds a lot like proof-
               | search in idris and agda (coq too, I thing), and it's
               | nicer than you think: you're very often working with
               | definition-stubs created by automated case-splitting,
               | which adds holes for you. Jumping around between holes
               | becomes how you program, not an irritating interruption.
               | 
               | But even aside from that, I don't think verb-first needs
               | to be a showstopper: given that we've got type
               | signatures, there's a lot of local context to work with.
               | You're probably calling a function on one or more of the
               | parameters, or else you're typing the leftmost-piece of a
               | composition chain that gives you your result type. So
               | throw Param1Type -> a, b -> ResultType etc at hoogle and
               | populate a completion list. Completion doesn't have to be
               | perfect to be useful. The hard part would be performance:
               | if completion isn't fast, what's the point?
        
               | still_grokking wrote:
               | > And it's perfectly possible to run hoogle locally and
               | integrate it with your editor.
               | 
               | Interesting.
               | 
               | Could you point to some demo of such IDE integration?
               | Never seen it.
               | 
               | I'm still struggling to imagine how something like
               | "IntelliSense" would look like in such a system. Do you
               | have e.g. any demo video you could point to? Curious to
               | learn more!
        
               | zopa wrote:
               | If I made it sound like there's something like
               | IntelliSense today, apologies! We've got
               | <https://github.com/haskell/haskell-
               | mode/blob/master/haskell-...>, but it's type-a-command-
               | and-do-a-search: it's not linked in with completion
               | directly in the setups I've seen.
               | 
               | (In practice, I'm usually starting from a slightly
               | different place: I know I want a Frob and I've got a This
               | and a That, so I do :hoogle This -> That -> Frob and get
               | some options. The thought-process is working backwards
               | from the goal more than forwards from one key object in
               | focus. A different way of working, but I'm not convinced
               | it's less effective.)
               | 
               | My point though was that it's an engineering issue, not a
               | fundamental language limitation. ie not a reason all
               | future languages should shun haskell features. The
               | building blocks to do better at completion than haskell
               | curently does are there.
        
               | lolinder wrote:
               | > The other part is: Records are no substitute for
               | objects. Not even close. Those are just quite primitive
               | structs. (To learn how unpractical is it to try to build
               | objects from structs without proper language support just
               | ask someone who was forced to use C after coming from a
               | more complete OO language).
               | 
               | I agree with you about C and Haskell's records, but I'm
               | curious if you'd say the same about Rust's struct + impl
               | system? Are there problems that can only be solved with
               | real, Smalltalk-inspired objects, or can lightweight
               | structs do the job if supported by enough syntactic
               | sugar?
        
               | still_grokking wrote:
               | The answer lies in the answer to why Rust added `dyn
               | traits`...
               | 
               | Indeed Rust striked some kind of sweet spot because it
               | got the _defaults_ right.
               | 
               | Syntactic it mimics mostly the OOP approach, but without
               | the conceptional burdens behind it.
               | 
               | Still Rust could not do without dynamic dispatch (which
               | is the--wrong--default in OOP).
               | 
               | In the (admittedly) seldom cases where you need dynamic
               | dispatch & _runtime_ polymorphism you just need them.
               | 
               | You could build this stuff by hand (and people did in the
               | past in languages without this features built-in) but
               | having dedicated language level support for that makes it
               | much more bearable.
               | 
               | Structs + the impl system is static dispatch. This just
               | can't replace dynamic dispatch. If it could nobody would
               | have ever invented v-tables...
        
               | pera wrote:
               | Your first point is also true for procedural programming
               | languages, but at least in Haskell you know that if
               | something is, say, a functor then you know what sort of
               | things you can do with that value. I think it should be
               | possible for an IDE to suggest functions if you used the
               | reverse application operator:                 [1, 2, 3] &
               | ^-- suggestion here
               | 
               | Unfortunately this wouldn't be very idiomatic in Haskell,
               | maybe in Idris with |> this would make more sense?
        
               | still_grokking wrote:
               | > if something is, say, a functor then you know what sort
               | of things you can do with that value
               | 
               | Sure. Because you memorized all the functor methods and
               | remembered that there is a functor instance defined for
               | the data type at hand... ;-)
               | 
               | > Unfortunately this wouldn't be very idiomatic in
               | Haskell, maybe in Idris with |> this would make more
               | sense?
               | 
               | Or you could just admit that the "OOP style syntax" is
               | superior. (I'm not saying that OOP is superior, though)
        
               | skavi wrote:
               | With Haskell, you learn to discover in a different way.
               | Just think about the shape of the function you'd want,
               | then type that into Hoogle. I learned Rust before
               | Haskell, but prefer Hoogle to Rust's searching via dot
               | chaining.
        
               | still_grokking wrote:
               | > Just think about the shape of the function you'd want,
               | then type that into Hoogle.
               | 
               | Do you _really_ think this is a adequate replacement for
               | proper IDE support?
        
               | likeclockwork wrote:
               | All you work with is method calls? No free functions? No
               | library functions?
               | 
               | I perform operations on stuff, if I don't know the name
               | of the operation I intend to perform I clearly have some
               | reading to do. Integrated look up for one specific class
               | of operation which isn't even omnipresent in Class-
               | oriented languages isn't a killer feature for me. Nor is
               | structuring every module even if it's completely
               | stateless as a class, just to benefit from IDE driven
               | development a reasonable price to pay.
        
           | deltasevennine wrote:
           | This opinion is also biased. We have no theoretical method
           | for determining which design philosophy is better than the
           | other.
           | 
           | We can't know whether the OOP religion is better, we also
           | can't know if the Haskell religion is better, and we can't
           | know whether NEITHER is better. (this is key, even the
           | neutral point of view where both are "good" can't be proven).
           | 
           | We do have theories to determine algorithmic efficiency.
           | Computational complexity allows us to quantify which
           | algorithm is faster and better. But whether that algorithm
           | was better implemented using FP concepts or OOP concepts, we
           | don't know... we can't know.
           | 
           | A lot of people like you just pick a random religion. It may
           | seem more reasonable and measured to pick the neutral ground.
           | But this in itself is A Religion.
           | 
           | It's the "it's all apples and oranges approach" or the "FP
           | and OOP are just different tools in a toolbox" approach....
           | but without any mathematical theory to quantify "better"
           | there's no way we can really ever know. Rotten apples and
           | rotten oranges ALSO exist in a world full of apples and
           | oranges.
           | 
           | You can't see it but even on an intuitive level this
           | "opinion" is really really biased. It seems reasonable when
           | you have two options to choose from "OOP" and "FP", but what
           | if you have more options? We have Declarative programming,
           | Lisp style programming, assembly language programming, logic
           | programming, reg-exp... Are we really to apply this
           | philosophy to ALL possible styles of programming? Is every
           | single thing in the universe truly apples and oranges or just
           | a tool in a toolbox?
           | 
           | With this many options it's unlikely. Something must be bad,
           | something must be good and many things are better then other
           | things.
           | 
           | I am of the opinion that normal Procedural and imperative
           | programming with functions is Superior to OOP for the
           | majority of applications. I am not saying FP is better than
           | imperative programming, I am saying OOP is a overall a bad
           | tool even compared with normal programming. But I can't prove
           | my opinion to be right, and you can't prove it to be wrong.
           | 
           | Without proof, all we can do is move in circles and argue
           | endlessly. But, psychologically, people tend to fall for your
           | argument because it's less extreme, it seemingly takes the
           | "reasonable" mediator approach. But like I said even this
           | approach is one form of an extreme and it is not reasonable
           | at all.
           | 
           | I mean your evidence is just a bunch of qualitative factoids.
           | An opponent to your opinion will come at you with another
           | list of qualitative factoids. You mix all the factoids
           | together and you have a bigger list of factoids with no
           | definitive conclusion.
        
             | com2kid wrote:
             | > Computational complexity allows us to quantify which
             | algorithm is faster and better. But whether that algorithm
             | was better implemented using FP concepts or OOP concepts,
             | we don't know... we can't know.
             | 
             | The CPUs code runs on are imperative, with a lot of
             | complexities and details hidden from programmers by magic
             | the CPU does involving things like reordering and automatic
             | parallelization.
             | 
             | However, none of the current languages are great at writing
             | code that maps to how the CPU works. One can comment that
             | functional programming does a better job of breaking up
             | data dependencies, but imperative code can also do that
             | just fine.
             | 
             | The problem with mapping paradigms to performance is that
             | none of the paradigm purists _care_ about performance, end
             | of the day they care about theoretical purity.
             | 
             | CPUs don't care about paradigms, they care about keeping
             | execution units busy and cache lined filled up.
        
             | rileyphone wrote:
             | > without any mathematical theory to quantify "better"
             | there's no way we can really ever know. Rotten apples and
             | rotten oranges ALSO exist in a world full of apples and
             | oranges.
             | 
             | So you believe that the only way things can be compared is
             | on quantitative measurements? Not with how they impress
             | their users within whatever context they're in?
             | 
             | > I mean your evidence is just a bunch of qualitative
             | factoids. An opponent to your opinion will come at you with
             | another list of qualitative factoids. You mix all the
             | factoids together and you have a bigger list of factoids
             | with no definitive conclusion.
             | 
             | This is the process in which we gain knowledge in an
             | uncertain world. I guess you could take the nihilistic
             | stance and ignore it, but what's the use of arguing with
             | nihilists?
        
             | Supermancho wrote:
             | > We have no theoretical method for determining which
             | design philosophy is better than the other.
             | 
             | We do have a theoretical method. It's the scientific
             | method. Other than that, I'm largely of the same thinking.
             | Also, confusing language implementation with overall design
             | is a major source of confusion (eg Java vs OOP vs Erlang vs
             | FP vs Haskell, etc)
             | 
             | How to measure "better" and how the data is interpreted,
             | are the major stopping points to improving software
             | language usability. There have been some attempts (re:
             | Quorum). Classic OOP (inheritance, et al) is simpler to use
             | than mixins for many projects. So now we have to worry
             | about project size as another axis. Then we have to address
             | the issue of median developer effort. What about memory?
             | How do you weigh FP allocate-stack-as-a-for-loop vs reduced
             | mutability? It's more complex than FP good OOP bad.
        
               | deltasevennine wrote:
               | >We do have a theoretical method. It's the scientific
               | method.
               | 
               | Science is limited. That being said this isn't part of
               | science at all. Programming is more the domain of logic
               | and maths which is entirely different from science which
               | is more data driven.
               | 
               | >How to measure "better" and how the data is interpreted,
               | are the major stopping points to improving software
               | language usability. There have been some attempts (re:
               | Quorum). Classic OOP (inheritance, et al) is simpler to
               | use than mixins for many projects. So now we have to
               | worry about project size as another axis. Then we have to
               | address the issue of median developer effort. What about
               | memory? How do you weigh FP allocate-stack-as-a-for-loop
               | vs reduced mutability? It's more complex than FP good OOP
               | bad.
               | 
               | I mean this is your opinion. I don't see any logic or
               | science here. Just another factoid.
        
               | Supermancho wrote:
               | > That being said this isn't part of science at all.
               | 
               | Human behavior (and usability at-large) is subject to
               | scientific investigation and conclusions. Again, the
               | issue is data categorization and availability to conduct
               | studies.
               | 
               | > I mean this is your opinion.
               | 
               | I don't know what you're referring to, but it seems
               | spurious, based on available data.
               | 
               | [edit after following some other thread...you also say] >
               | But of course most members of either group have Not
               | actually went to space to verify the conclusions for
               | themselves.
               | 
               | "I don't know because I didn't experience it", trolling.
               | How quaint. Good luck with your navel gazing.
        
             | still_grokking wrote:
             | Nobody argued for any "better".
             | 
             | The point is: When things become a religion with cargo
             | culting acolytes even the "best" approaches stop making
             | sense.
             | 
             | That's completely independent of the concrete religion at
             | hand.
             | 
             | I did not argue to "pick sides"!
             | 
             | In the end all the approaches are just tools. You need to
             | wield them wisely for optimal results.
        
               | deltasevennine wrote:
               | This is the problem. You didn't even read my argument. Go
               | read it again, carefully, instead of skimming through it.
               | 
               | My point is:
               | 
               | Maybe one of these religions is right. Maybe something is
               | the best. Maybe a side must be picked.
               | 
               | You didn't argue for better. You argued that everything
               | is the same, that all things are good and nothing is bad
               | and that every single thing in the programming universe
               | is a tool in a toolbox.
               | 
               | I disagree. Violently.
               | 
               | The point is neither the culting acolytes OR people like
               | you can prove it either way.
               | 
               | But calling people who don't share your opinion as
               | "culting acolytes" is manipulative. The words have
               | negative connotations and it's wrong. Extreme opinions in
               | science and logic are often proven to be true, they are
               | often validated. To assume that anyone without a neutral
               | opinion is a cultist is very biased in itself.
               | 
               | Here's a good analogy: I believe the world is round. I'm
               | an extremist. You on the other hand embrace all theories
               | as tools in a toolbox. The world could be round or it
               | could be flat, your the reasonable neutral arbiter taking
               | neither the side of the flat-earther or round-earther.
               | 
               | The illusion now is more clear. All 3 sides are a form of
               | bias, but clearly our science says only one of these
               | sides is true, and this side is NOT the "neutral arbiter"
               | side
        
               | still_grokking wrote:
               | I did not argue for "everything is the same".
               | 
               | Quite the contrary.
               | 
               | I've said: _Everything depends on context._
               | 
               | What makes sense for Haskell does not necessary make
               | sense for other languages.
               | 
               | Also there is no "side" that needs to be picked. What's a
               | good idea in one context could be a terrible idea in some
               | other context.
               | 
               | But people are copying blindly Haskell lately.
               | 
               | The issue is that this happens _blindly_ -- again without
               | questioning anything about the underlying premises.
               | 
               | Doing so is called "cargo culting". And that's something
               | done by acolytes. (The words are loaded for a reason,
               | btw.)
               | 
               | I'm coming from a language (Scala) where it took almost
               | 15 years to recognize that Haskell isn't anything that
               | should be imitated. Now that most people there start to
               | get it people elsewhere start to fall for the exact same
               | fallacy. But this time this could become so big that this
               | will end up like the "OOP dark ages" which we're just
               | about to finally leave. People are seemingly starting to
               | replace one _religion_ with the other. This won 't make
               | anything better... It's just equally stupid. It makes no
               | difference whether you replace one "hammer" with another
               | but still pretend that everything is a nail.
        
               | deltasevennine wrote:
               | You did argue for everything is the same. Basically by
               | "same" I mean everything is "equally good" depending on
               | context. The whole hammers are for hammering and
               | screwdrivers are for screwing thing... I explicitly said
               | your argument was that everything was a tool in a toolbox
               | and you exactly replicated what I said.
               | 
               | My point is: something can be truly bad and something can
               | be truly good EVEN when considering all possible
               | contexts.
               | 
               | You can't prove definitively whether this is the case for
               | FP or OOP or any programming style for that matter. You
               | can't know whether someones "side" is a cargo cult or not
               | when there's no theoretical way for measuring this.
               | 
               | The cultish following may even be correct in the same way
               | I cargo cult my belief that the world is ROUND and not
               | flat.
        
               | hutzlibu wrote:
               | "You did argue for everything is the same."
               | 
               | I do not see where he did that. He argued simply that
               | context matters. (And yes a "bad" tool can be the right
               | tool, if it is the only tool avaiable.)
               | 
               | "My point is: something can be truly bad and something
               | can be truly good EVEN when considering all possible
               | contexts."
               | 
               | And diving deeper into philosophy here, can you name one
               | example?
        
               | deltasevennine wrote:
               | >I do not see where he did that. He argued simply that
               | context matters. (And yes a "bad" tool can be the right
               | tool, if it is the only tool avaiable.)
               | 
               | Well I see it. If you don't see it, I urge you to reread
               | what he said.
               | 
               | A bad tool can be the right tool but some tools are so
               | bad that it is never the right tool.
               | 
               | >And diving deeper into philosophy here, can you name one
               | example?
               | 
               | Running is better then walking for short distances when
               | optimizing for shorter time. In this case walking is
               | definitively "bad." No argument by anyone.
               | 
               | Please don't take this into a pedantic segway with your
               | counter here.
        
               | 0xdeadbeefbabe wrote:
               | Not deltasevennine, but giving the CPU fewer things to do
               | sounds good to me (in any context), even if it is
               | currently unpopular. Some cults are popular and some
               | aren't.
        
               | hutzlibu wrote:
               | "Not deltasevennine, but giving the CPU fewer things to
               | do sounds good to me (in any context)"
               | 
               | Ah, but what if you are freezing and that CPU is your
               | only heat source ...
        
               | still_grokking wrote:
               | > My point is: something can be truly bad and something
               | can be truly good EVEN when considering all possible
               | contexts.
               | 
               | No, that's impossible. "Truly good" or "truly bad" are
               | moral categories. Something closely related to religion,
               | BTW...
               | 
               | > You can't know whether someones "side" is a cargo cult
               | [...]
               | 
               | Of course I can.
               | 
               | If it _objectively_ makes no sense (in some context), and
               | is only blindly copied from somewhere else _without
               | understanding why there things were done the way they
               | were done_ , this is called "cargo cult". That's the
               | definition of this term.
               | 
               | How can I tell whether there is no understanding behind
               | something? If the cultists would understand what they are
               | actually copying they wouldn't copy it at all. ;-)
               | 
               | Replacing methods with free standing functions is for
               | example on of such things: In Haskell there are no
               | methods. So free standing functions are all you have. But
               | imitating this style in a language with methods makes no
               | sense at all! It complicates things _for no reason_. This
               | is obviously something where someone does not understand
               | why Haskell is like it is. They just copy on the syntax
               | level something that they think is  "functional
               | programming". But surface syntax should not be missed for
               | the actual concepts! Even it's easy to copy the syntax
               | instead of actually adapting the ideas behind it (only
               | where it makes sense of course!).
        
               | deltasevennine wrote:
               | >No, that's impossible. "Truly good" or "truly bad" are
               | moral categories. Something closely related to religion,
               | BTW...
               | 
               | Wrong. Good and bad is used in a fuzzy way here, I'm
               | OBVIOUSLY not talking about morality OR religion. What I
               | am talking about are things that can be potentially
               | quantified to a formal theory. For example we know the
               | shortest distance between two points is a line. We have
               | formalized algorithmic speed with computational
               | complexity theory. O(N) is definitively more "good" then
               | O(N^2).
               | 
               | Right now we don't have optimization theory or formal
               | definitions on logic organization. We can't quantify it
               | so we resort to opinionated stuff. And the whole thing
               | goes in circles. But that is not to say this is
               | impossible to formalize. We just haven't yet so all
               | arguments go nowhere. But the shortest distance between
               | two points? Nobody argues about that (I hope some
               | pedantic person doesn't bring up non-euclidean geometry
               | because come on).
               | 
               | All we can say right now is because there is no theory,
               | nothing definitive can be said.
               | 
               | >Of course I can. >If it objectively makes no sense (in
               | some context), and is only blindly copied from somewhere
               | else without understanding why there things were done the
               | way they were done, this is called "cargo cult". That's
               | the definition of this term.
               | 
               | You can't. The definition of bias is that the person who
               | is biased is unaware of it. You can talk with every
               | single religious person in the world. They all think they
               | arrived at their beliefs logically. Almost everyone
               | thinks the way they interpret the world is logical and
               | consistent and it makes sense. They assume everyone else
               | is wrong.
               | 
               | To be truly unbiased is to recognize the possibility of
               | your own fallibility. To assume that your point of view
               | is objective is bias in itself. You ask those people who
               | "blindly" copy things if they did it blindly, they will
               | tell you "No." They think they're conclusions are logical
               | they don't think they're blind. The same way you don't
               | think your blind, the same way I don't think I'm blind.
               | All blind people point at other blind people and say
               | everyone else is blind except for them.
               | 
               | The truly unbiased person recognizes the possibility of
               | their own blindness. But almost nobody thinks this way.
               | 
               | Nobody truly knows who is blind and who is not. So they
               | argue endlessly and present factoids to each other like
               | this one here you just threw at me:
               | 
               | "Replacing methods with free standing functions is for
               | example on of such things: In Haskell there are no
               | methods. So free standing functions are all you have. But
               | imitating this style in a language with methods makes no
               | sense at all! It complicates things for no reason. This
               | is obviously something where someone does not understand
               | why Haskell is like it is. They just copy on the syntax
               | level something that they think is "functional
               | programming". But surface syntax should not be missed for
               | the actual concepts! Even it's easy to copy the syntax
               | instead of actually adapting the ideas behind it (only
               | where it makes sense of course!)."
               | 
               | I mean how do you want me to respond to this factoid?
               | I'll throw out another factoid:
               | 
               | Forcing people to use methods complicates things for no
               | reason. Why not just have state and logic separated? Why
               | force everything into some horrible combination? If I
               | want to use my method in another place I have to bring
               | all the state along with it. I can't move my logic
               | anywhere because it's tied to the contextual state. The
               | style of the program itself is a weakness and that's why
               | people imitate another style.
               | 
               | And boom. What are you gonna do? Obviously throw another
               | factoid at me. We can pelt each other with factoids and
               | the needle doesn't move forward at all.
        
               | still_grokking wrote:
               | > Forcing people to use methods complicates things for no
               | reason.
               | 
               | No, it doesn't.
               | 
               | All functions are in fact objects and most are methods in
               | JavaScript, and there is nothing else.
               | 
               | Methods (== properties assigned function object values)
               | are the natural way to express things in JavaScript.
               | 
               | Trying to pretend that this is not the case, and trying
               | really hard to emulate (free) functions (which, to stress
               | this point once more, do not exist in JavaScript) makes
               | on the other hand's side everything more complicated than
               | strictly needed.
               | 
               | > Why not just have state and logic separated?
               | 
               | That's a good idea.
               | 
               | This is also completely orthogonal to the question on how
               | JavaScript is supposed to be used.
               | 
               | JavaScript is a hybrid langue. Part Small Talk, part
               | Lisp.
               | 
               | It's common in JavaScript since inception to separate
               | data (in the form of objects that are serializable to and
               | from JSON) from functionality (in the form of function
               | objects).
               | 
               | JavaScript was never used like Java / C++ / C#, where you
               | glue together data and functionality into classes, and
               | still isn't used like that (nevertheless they've got some
               | syntax sugar called "class" at some point).
               | 
               | > Why force everything into some horrible combination?
               | 
               | Nobody does that. At least not in JavaScript.
               | 
               | Still that does permit to use methods.
               | 
               | Functions themself are objects. Using objects is the
               | natural way for everything in JavaScript as there is
               | nothing else than objects. Everything in JavaScript is an
               | object. And any functionality the language provides is
               | through methods.
               | 
               | Working against the basic principles of a language is a
               | terrible idea! (In every language, btw). It complicates
               | everything for no reason and has horrible code
               | abominations as a consequence.
               | 
               | > If I want to use my method in another place I have to
               | bring all the state along with it.
               | 
               | No, you don't. You need only to bring the data that you
               | want to operate on.
               | 
               | The nice thing is: You get the functionality right at the
               | same place as the data. You don't need to carry around
               | anything besides the data that you work on.
               | 
               | The alternative is needing to bring the modules that
               | carry the functionality that you want to apply to the
               | data you need also to have around... As an example:
               | `items.map(encode)` is nicer to write and read than
               | `List.map items encode`.
               | 
               | You don't need to carry around the `List` module when the
               | method can already be found on the prototype of the data
               | object. Also it's more clear what's the subject and
               | what's the object of the operation.
               | 
               | > I can't move my logic anywhere because it's tied to the
               | contextual state.
               | 
               | That's just not true in JavaScript.
               | 
               | Nothing is easier then passing functions objects around,
               | or change the values of properties that reference such
               | function objects.
               | 
               | JavaScript is one of the most flexible languages out
               | there in this regard!
               | 
               | You can even rewrite built-in types while you process
               | them. (Not that I'm advocating for doing so, but it's
               | possible).
               | 
               | > The style of the program itself is a weakness [...]
               | 
               | You did not present any facts that would prove that
               | claim.
               | 
               | > [...] that's why people imitate another style.
               | 
               | No, that's not the reason.
               | 
               | You don't need to imitate Haskell when you want to write
               | functional programs in a Lisp derived language... ;-)
               | 
               | People are obviously holding some cargo cult ceremonies
               | when trying to write Haskell in JavaScript.
               | 
               | Your other opinions are based on wrong assumptions. I'm
               | not going into that in detail, but some small remarks:
               | 
               | > For example we know the shortest distance between two
               | points is a line.
               | 
               | In Manhattan1? ;-)
               | 
               | > O(N) is definitively more "good" then O(N^2).
               | 
               | Maybe it's more "good"...
               | 
               | But it's for sure not always faster, or even more
               | efficient, in reality.
               | 
               | Depending on the question and your resources (e.g.
               | hardware) a brute force solution may be favorable against
               | a solution with a much lower complexity _on paper_.
               | 
               | Welcome to the physical world. Where practice differs
               | from theory.
               | 
               | > But the shortest distance between two points? Nobody
               | argues about that (I hope some pedantic person doesn't
               | bring up non-euclidean geometry because come on).
               | 
               | You don't need to look into non-euclidean geometry.
               | 
               | Actually, even there the shortest distance between two
               | points is a "straight line". Only that the straight line
               | may have some curvature (because of the curved space).
               | 
               | But you didn't even consider that "distance" is actually
               | something2 about that one can actually argue...
               | 
               | > You can't. The definition of bias is that the person
               | who is biased is unaware of it.
               | 
               | No, that's not the definition3.
               | 
               | > Nobody truly knows who is blind and who is not.
               | 
               | Nobody truly knows anything.
               | 
               | What's the point?
               | 
               | What was actually the point of your comment, btw?
               | 
               | ---
               | 
               | 1 https://en.wikipedia.org/wiki/Taxicab_geometry 2
               | https://en.wikipedia.org/wiki/Distance 3
               | https://en.wikipedia.org/wiki/Bias
        
               | [deleted]
        
               | _gabe_ wrote:
               | > I believe the world is round
               | 
               | This isn't an opinion or a belief, it's a verifiable
               | fact. We know the world is round because: if you travel
               | east you'll eventually arrive at your starting
               | destination; if you stand on a ship's crow's nest you can
               | see further than the crew on the deck because of the
               | curvature of the earth; if you fly a plane and make two
               | 90 degree turns and travel an equal distance, you will
               | end up at your starting point due to the curvature of the
               | earth; if you go to space in a space station, you can
               | visually verify that the earth is round.
               | 
               | Cargo culting acolytes will believe the earth is round
               | with no explanation as to why. Just because you believe
               | the right thing doesn't mean you're not cargo culting. If
               | you can't explain why you believe what you believe,
               | you're simply believing to follow a particular crowd,
               | regardless of the validity of the belief.
        
               | deltasevennine wrote:
               | Sure.
               | 
               | I simply use this "world" example because everyone here
               | is in the same cult as me: "The world is round cult."
               | When I use it, they get it. If I were speaking to a
               | different cult, I would use a different example.
               | 
               | You will note, both flat earthers and non-flat earthers
               | have very detailed and complex reasoning for why they
               | "believe" what they believe. But of course most members
               | of either group have Not actually went to space to verify
               | the conclusions for themselves.
        
               | awgm wrote:
               | yeah but sometimes its useful to use a flat earth model
               | when for instance the ground youre going to build
               | something like a shed on is relatively flat. in the big
               | picture sense i agree but in different contexts an
               | alternative abstract model can suffice and actually be
               | more efficient if the aim is to build the shed in this
               | case
        
               | AnimalMuppet wrote:
               | Nope. You're the one who isn't listening or
               | understanding. still_grokking's point is that _even if_
               | one approach is better than the other, a slavish cargo-
               | cult adherence to that approach will still produce bad
               | results.
        
               | still_grokking wrote:
               | Thanks! Couldn't say this better.
               | 
               | I'm not arguing about the approaches as such, I've stated
               | that cargo culting around any of them is a bad thing by
               | itself.
               | 
               | Blindly imitating something for which you didn't fully
               | grasp all pros and cons will at best not help you and in
               | most cases make things worse.
        
               | deltasevennine wrote:
               | Nope. You aren't listening to me. I am getting exactly
               | what he's saying. What I am saying is that the cargo
               | culters could be right. You don't know. Nobody knows.
               | 
               | Additionally he DID say that the approaches were all
               | tools in a toolbox.
        
           | ladyattis wrote:
           | I'm biased but I find the pattern for FP in LISP-like
           | languages easier to understand. I think that and other
           | languages with FP facilities are better to emulate than
           | Haskell which seems more focused on mathematicians.
        
         | toastal wrote:
         | Totally agreed. Coworkers will hate you if you start mixing in
         | these styles into an existing code base. If you want to do FP,
         | go switch languages (and likely jobs/teams) to something where
         | the ergonomic are clear, concise, and idomatic--then the
         | benefits become more obvious. It's a bit like teaching object-
         | orientation through OCaml... just because you can, doesn't mean
         | the community recommends it generally.
        
           | agentultra wrote:
           | Javascript is a multi-paradigm language as are most others
           | people are mentioning in these threads. It shows in the
           | specification for the language too: higher-order functions,
           | anonymous functions, Array.map/filter/reduce, etc. Like it or
           | not the language has facilities to enable programming in a
           | functional style.
           | 
           | There are advantages to this approach like enabling different
           | styles when appropriate.
           | 
           | There are disadvantages as well: you rely on the discipline
           | of the programmers or tools to catch mistakes.
           | 
           | But there's nothing inherently _wrong_ about thinking of
           | programs in terms of FP ideas. There are other ways to think
           | about programming than in terms of program counters, control
           | flow statements, and procedures. It 's not even idiomatic
           | Javascript to write code that way!
           | 
           | JS is a more functional language than most people seem to
           | think.
           | 
           | The tragic thing about TFA is that it's not an article but a
           | chapter in a long series of posts and this is just one step
           | along the way to showing how an FP style _can_ manage the
           | complexities of a non-trivially large JS code base.
        
             | toastal wrote:
             | I won't disagree that JavaScript isn't multi-paradigm and
             | you _can_ write in a functional style, but you have to look
             | at where the ergonomics are:
             | 
             | * dot, `.`, syntax on objects vs. composition/pipe
             | operators
             | 
             | * no autocurry
             | 
             | * no ADTs or basic pattern matching
             | 
             | * has null + undefined but no Maybe/Option (there is null
             | coalescing and null chaining, but it's easy to accidentally
             | skip)
             | 
             | * const can still mutate the on the object, freeze incurs a
             | massive performance cost
             | 
             | * no tail-call optimization outside Safari despite being in
             | the ECMA2015 spec
             | 
             | * `class` keyword existed and private methods and values
             | now, FP is pretty anti-encapsulation
             | 
             | * no immutable data structures in the stdlib
             | 
             | * no way to prevent side effects (/* __PURE__ */ in code
             | generation is a hack)
             | 
             | Can you get benefits from avoiding state/mutation and
             | choosing composition over inheritance? Sure, but it's
             | nothing like being in a language where these aren't
             | something you _can_ do or the default, but the _only_ way
             | to write code and having the tool to express it.
        
               | agentultra wrote:
               | It's a mess for sure and you'll never get a reasonable FP
               | language from it. You won't get a Smalltalk out of it
               | either. Instead we get a mish-mash of ideas hashed
               | together by a committee of people with differing
               | backgrounds, experiences, and ideas.
               | 
               | ... but some of those FP ideas are pretty neat and when
               | used well can make code that is easier to maintain (for
               | people who are familiar with the concepts).
        
               | rileyphone wrote:
               | It's actually fairly easy to get most of a Smalltalk out
               | of Javascript. Prototypes and first-class functions form
               | a really powerful basis for a higher language. Though, to
               | your point, it wouldn't really still be Javascript.
        
               | rory wrote:
               | Do you know of an example snippet / article demonstrating
               | how to do this?
        
               | rileyphone wrote:
               | Smalltalk in Self: nearly complete Smalltalk
               | implementation on similar prototypical language.
               | http://www.merlintec.com/download/mario.pdf
               | 
               | Mootools: ancient class system for Javascript.
               | https://mootools.net/core
               | 
               | Also, here's a very old Crockford article on implementing
               | classes in Javascript.
               | https://crockford.com/javascript/inheritance.html
        
               | wiseowise wrote:
               | You're implying that those things are necessary to write
               | reasonable functional programs. They're not.
        
               | agentultra wrote:
               | True. Reasonable to me is a pretty high bar. You can
               | write in a functional style in JS and feel it is
               | reasonable. You might feel differently after using
               | SML/OCaml/Haskell/etc.
        
           | tmountain wrote:
           | I love FP, but I wouldn't let someone introduce these
           | abstractions into our JavaScript code base, as they ramp up
           | the complexity in understanding code that can be represented
           | in a simpler fashion with the same results.
        
             | toastal wrote:
             | A loop isn't simpler than recursion or high-order functions
             | since it introduces state and is noisy, but most examples
             | of JavaScript/TypeScript + FP involve heavy usage of
             | utility libraries that aren't community standards (like a
             | Prelude). Not to say these libraries aren't valuable or of
             | good quality, but it's a lot to learn atop the language
             | itself for a new hire and can lead to some library lock-in
             | as said functions will end up all over the code. The folks
             | that preach the libraries the most are the ones that
             | usually want their JS/TS to look like Haskell which ends up
             | making it impossible for outsiders to follow (so now I need
             | to know JavaScript + TypeScript + Haskell + the weird
             | esoteric version these people write?). And those folks
             | should be allowed and encourage to just write some ML-
             | flavor-to-JavaScript code instead which can often be easier
             | to for a new hire to follow since all examples will follow
             | community standards (wouldn't be surprised if the coders
             | were happier writing it too).
        
         | AtNightWeCode wrote:
         | That example is what's called fluent code in OO in combination
         | with the builder pattern. To experience peak builder pattern
         | hell one should look at the Android API.
        
         | theptip wrote:
         | Thanks for this. I got the same growing sense of discomfort
         | reading the OP, that decomposing everything into operations
         | makes the code way harder to grok vs. just doing the entire
         | transform in one step.
         | 
         | I think the point being made was "each transform could be
         | reusable across your codebase", but I think for this example
         | you really pay a high comprehensibility cost. And duplicating a
         | few lines of code is often actually the right call, instead of
         | coupling two unrelated bits of code that happen to be saying
         | the same thing right now (but which will plausibly diverge in
         | the future).
         | 
         | As a new Rustacean, I do really like Result and Option, but
         | writing idiomatically in your language is really important too.
        
         | [deleted]
        
         | chris37879 wrote:
         | Exactly this. I realized that a lot of how I use objects fits
         | in nicely with FP patterns, but when I started looking into FP
         | "best practices" the number of times the best practice is
         | "Replicate this exact behavior from a 'more functional'
         | language, even though your language has idioms for that" is
         | astounding. I decided I'll just keep programming without side
         | effects, if that's what FP is.
        
       | RadixDLT wrote:
       | write more robust, maintainable code
        
       | Throwaway23459 wrote:
       | There's no agreed way to organise a functional codebase. You end
       | up with thousands of functions, can you imagine the mess a big
       | team is capable creating? With some discipline I suppose it could
       | work, but you would need some organising principle and some
       | serious discipline. Object oriented is organised by virtue of the
       | object paradigm.
        
         | piaste wrote:
         | > Object oriented is organised by virtue of the object
         | paradigm.
         | 
         | Or in other words, OO code ties business logic to presentation
         | logic. By sticking to the dominant 'one class per file'
         | principle, the same code behaves differently based only on
         | whether it appears in one file or two, so it's not trivial to
         | move code around to make it more organized.
         | 
         | When I write functional code, I first write all the functions
         | and types I need in a single file, without worrying about
         | presentation or naming until it compiles. Then, before
         | committing, I reorganize them into folders, files, and modules
         | so it's easier to read and navigate, and I can do it any way is
         | more appropriate (sometimes layer-first is more readable,
         | sometimes domain-first).
         | 
         | I can also split pure functions into chains of smaller, pure,
         | private functions if they're too long to follow (90% of the
         | time some functions end up being way longer than I expected),
         | which is _way_ simpler than splitting a large class into
         | smaller ones.
        
         | tempodox wrote:
         | The languages in the ML family have modules. They are the
         | agreed-upon way to organize code and control visibility in
         | those languages.
        
       | dluan wrote:
       | Nice writing style!
        
         | dluan wrote:
         | Also the markup font is a little wonky and `Ok` ends up looking
         | like `0`.
        
       | mike31fr wrote:
       | After reading this article, I changed my mind about functional
       | programming. I no longer think I need to learn it asap. I now
       | think it may actually make my code more difficult to understand
       | and maintain, and will keep avoiding such patterns.
        
         | runevault wrote:
         | Learn FP with a language designed to be FP instead of one that
         | has the tools for it but isn't primarily meant to be used that
         | way. See: Ocaml, f#, Haskell if you want to go all the way off
         | the deep end, etc.
        
       | BoppreH wrote:
       | I love softcore FP (immutability, first-class functions, etc),
       | but I always get the impression that hardcore FP, like in this
       | article, is about reimplementing programming language concepts on
       | top of the actual programming language used.
       | 
       | The pipe feels like a block of restricted statements, `peekErr`
       | and `scan` recreate conditionals, the Maybe monad behaves like a
       | try-catch here, etc.
       | 
       | Of course there are differences, like `map` working on both lists
       | and tasks, as opposed to a naive iteration. That's cool. But this
       | new programming language comes with limitations, like the
       | difficulty in peeking ahead or behind during the list iteration,
       | reusing data between passes, and not to mention the lost tooling,
       | like stack traces and breakpoints.
       | 
       | I've written many (toy) programming languages, the process is
       | exactly like this article. And it feels awesome. But I question
       | the wisdom of presenting all this abstract scaffolding as a
       | viable Javascript solution, as opposed to a Javascripter's
       | introduction to Haskell or Clojure, where this scaffolding _is_
       | the language.
        
         | daotoad wrote:
         | I agree 100%.
         | 
         | I've worked on some big TypeScript code bases that make heavy
         | use of sort of FP the article promotes; dealing with stack
         | traces and debugging the code is incredibly painful. Jumping
         | around between 47 layers of curried wrapper functions and
         | function composers that manage all state mostly in closures is
         | a real drag.
         | 
         | Until the tooling is better, I can't recommend these idioms for
         | real work.
         | 
         | TBF, there is a kind of beauty to the approach and as you
         | really dig into it and understand it, it can feel like a
         | revelation. There's something addictive about it. But any
         | feeling of joy is obliterated by the pain of tracing an error
         | in a debugger that isn't equipped to handle the idiom.
        
         | throw10920 wrote:
         | As a complement to what you said: a far better paradigm to
         | everything-must-be-purely-functional is "write as much of your
         | program as is practical in the functional style, and then for
         | the (hopefully small) remnant, just give it the side-effects
         | and mutation".
         | 
         | This leads to fewer errors than the imperative/object-oriented
         | paradigms, and greater development velocity (and quicker
         | developer onboarding, and better tools...) than the
         | 100%-purely-functional strategy.
         | 
         | Hopefully, over time, we'll get functional programming
         | techniques that can _easily_ model more and more of real-world
         | problems (while incurring minimal programmer learning curve and
         | cognitive overhead), making that remainder get smaller without
         | extra programmer pain - but we may never eliminate it
         | completely, and that 's ok. 100 lines of effectful code is
         | _far_ easier to examine and debug then _the entire application_
         | , and our job as programmers is generally not to write purely
         | functional code, but to build a software artifact.
         | 
         | The above applies to type systems, too, which is why gradual
         | typing is so amazing. Usually 99/.9% of a codebase can be
         | easily statically-typed, while the remaining small fraction
         | contains logic that is complex enough that you have to contort
         | your type system to address it, and in the process break
         | junior's developers' heads - often better to box it, add
         | runtime checks, and carefully manually examine the code then
         | resort to templates or macros parameterized on lifetime
         | variables or something equally eldritch.
         | 
         | (and, like the above, hopefully as time goes on we'll get more
         | advanced _and_ easier-to-use type systems to shrink that
         | remainder)
        
         | bongobingo1 wrote:
         | The only thing stopping Functional Programming from taking off
         | are functional programmers.
         | 
         | It took me years (and Elixir) to get past the "here are some
         | words, some mean what you think, some mean something completely
         | different to what you know, some mean almost the same thing.
         | Also here's 30 overloaded operators that you have to juggle in
         | your head and we wont introduce things like variables for
         | another 4 pages." without running back to something imperative
         | to actually _build something_.
         | 
         | Functional programming's great when you have immutability to
         | drop an entire class of bugs _and the mental energy that
         | accompanies that_ , can pass-around and compose-with small
         | functions easily which makes writing, testing and figuring much
         | simpler and can make your brain click that "its all data"
         | without trying to over complicate it by attaching methods to
         | it.
         | 
         | Honestly I think that's 90% of what the royal You needs to
         | understand to get FP and actually try it. Selling people on
         | "its all stateless man" or other ivory tower tripe is such
         | garbage because (as the tutorials always point out) a program
         | with no state is useless, and then the poor shmuck has to learn
         | about monads just to add a key to a map and print something at
         | which point they're asking "how was this better again?"
        
           | BoppreH wrote:
           | I think that's a bit harsh. It's frustrating to translate an
           | imperative task to an FP language, but it's also frustrating
           | to translate a Bash command into Python, or Prolog semantics
           | into Go, or any program full of mutations and global state
           | into (safe) Rust.
           | 
           | I think a lot of the friction you mentioned comes from
           | learning imperative programming first. Our vocabulary, tools,
           | and even requirements come with an implicit imperative
           | assumption.
           | 
           | PS: I didn't downvote you, though your tone is harsher than I
           | prefer for HN.
        
             | bongobingo1 wrote:
             | > I think a lot of the friction you mentioned comes from
             | learning imperative programming first. Our vocabulary,
             | tools, and even requirements come with an implicit
             | imperative assumption.
             | 
             | Yes that's exactly my point and why no one cares about how
             | great a monad is when trying to learn FP.
        
               | wiseowise wrote:
               | How is that a problem of functional programming? When you
               | learn a language you don't start with "Well in English we
               | say..." you learn language with its idioms and quirks.
        
               | Izkata wrote:
               | > When you learn a language you don't start with "Well in
               | English we say..." you learn language with its idioms and
               | quirks.
               | 
               | Idioms and quirks come after rote memorization of basic
               | vocabulary and sentence structure, which are then used to
               | learn the idioms and quirks. I think Bongo is saying FP-
               | ers are skipping the basic vocabulary part and jumping
               | straight to the idioms and quirks.
               | 
               | It was interesting in 2015/2016 to see co-workers learn
               | some of that basic vocabulary of functional programming
               | without realizing they were touching on it, using
               | map/fold/etc when learning React.
        
               | bongobingo1 wrote:
               | It's not. It's a problem with people trying to sell FP to
               | non FP programmers. A non FP programmer doesn't care
               | about monads. They care about making what they already do
               | simpler and clearer.
        
               | wiseowise wrote:
               | Fair enough. I guess it's the same as when you're trying
               | to teach imperative programming starting from classes and
               | OOP.
        
             | shrimpx wrote:
             | I would argue that command sequences that mutate global
             | state are far more intuitive to humans (food recipes,
             | furniture assembly manuals, the steps to take to fix a flat
             | tire on your bike, etc.) than functions. So it's not just
             | what we learn first in a pedagogic sense. We're already
             | wired for imperative programming. "Thread the state of the
             | world through the food recipe instructions" is a ridiculous
             | concept to a normal person.
        
               | olddustytrail wrote:
               | > "Thread the state of the world through the food recipe
               | instructions"
               | 
               | Oh, that's how it works? That actually makes sense.
               | Thanks!
        
               | kaba0 wrote:
               | I think it is very dependent on the problem at hand.
               | 
               | Some traditional CS algorithm? Mutable it is. But a
               | compiler with different passes is a great fit for the FP
               | paradigm.
               | 
               | But even if we go to pure math, you will have
               | constructive proofs beside traditional ones.
        
               | senand wrote:
               | I agree in principle. However, if you work imperatively,
               | you'll use _much_ more (global) state than if you worked
               | with a pragmatic functional language like Clojure. Which
               | in turn leads to normal people not understanding what's
               | going on, since humans are built to keep, say, 10 things
               | (atoms) in mind, not 100.
        
             | revskill wrote:
             | s = 1; s = 2;
             | 
             | is same as
             | 
             | unit(1).chain(add(1))
             | 
             | That's the beauty of immutable data.
        
             | skrtskrt wrote:
             | I strongly disagree, it is definitely the teachers and
             | advocates of FP which are lacking.
             | 
             | There are plenty of programs and libraries written in
             | "imperative" languages like Python with lots of functional
             | style applied. That should be the starting point, not
             | sermonizing about whether a monad can even be defined with
             | English words.
        
               | alexvoda wrote:
               | Of course you can use English words. To quote:
               | 
               | "A monad is just a monoid in the category of
               | endofunctors, what's the problem?"
               | 
               | /s
        
               | TheOtherHobbes wrote:
               | Haskell is particularly, egregiously bad for this.
               | 
               | None of the concepts are particularly complex. They're
               | unfamiliar, sort of, but they're not insanely obscure.
               | 
               | But then there's the labelling. If an ordinary for-loop
               | was called a yarborough and a function call a demicurry
               | it _really_ wouldn 't help with the learning.
               | 
               | I realise the concepts are supposed to map[1] to category
               | theory, but category theory stole words like monad from
               | elsewhere anyway.
               | 
               | [1] Ha.
        
           | rkangel wrote:
           | I agree that Elixir is the ideal gateway into FP. It's also
           | quite a good argument that "FP" at its core is something more
           | fundamental than what is talked about in this article. Elixir
           | doesn't really use many of the category theory derived
           | approaches at all, it has a convenient way of doing method
           | chaining and some higher order function stuff and that's
           | about it. And the results are excellent code.
           | 
           | The two main FP things that you need to learn to do Elixir
           | well (IMO) are thinking about data structures first, and
           | purity. Choose the right representation of the data at each
           | stage and _then_ what functions do you need to move between
           | each. Make those functions side effect free (but not
           | obsessively). Then you put your stateful code in GenServers
           | and you have useful real code and most of it was incredibly
           | easy to test.
        
             | skydhash wrote:
             | Pretty much this. I've been learning Common Lisp and the
             | way I try to design my programs is to have a somewhat clear
             | understand on how your data should transform from input to
             | output. Then you write the functions.
             | 
             | Let's say your data is a log file and you want to load
             | everything in memory. You write the code that returns the
             | data, which you either store in a variable or compose with
             | other functions. At the end, you compose all of these
             | functions in your programs. Everything is an expression,
             | meaning that you can extract things easily into functions.
             | This is how you make things readable. `load-log-from-file`
             | and `auth-failure-count` is better than keeping everything
             | together in a single function.
        
           | nailer wrote:
           | > Functional programming's great when you have immutability
           | to drop an entire class of bugs and the mental energy that
           | accompanies that, can pass-around and compose-with small
           | functions easily which makes writing, testing and figuring
           | much simpler and can make your brain click that "its all
           | data" without trying to over complicate it by attaching
           | methods to it.
           | 
           | A hundred percent. FP for me, is "let's stop gluing state and
           | functions together for no reason" and get all the benefits
           | above. I understand pure functions, avoiding state, closures,
           | and using first class functions as the basic building blocks
           | of creating higher level structures.
           | 
           | When it becomes "a functor is a monoid of the schlerm
           | frumulet" - ala the typical FP advocacy blog / latest React
           | state management manifesto masquerading as library
           | documentation, I zone out. The odd thing is, I don't feel
           | I've lost anything by doing so.
        
         | disantlor wrote:
         | "softcore FP" is a great way to put it.
         | 
         | JS with Ramda (and an FRP library, if needed) is the sweet spot
         | for me. I use a lot of pipes() but usually don't break them
         | down into smaller functions until there is a reason to; but FP
         | makes it trivial to do so.
        
       | zigzag312 wrote:
       | Improved type system to me is the most valuable. Compared to OO
       | inheritance fest, designing with types popular in functional
       | languages can be much more natural and easier to maintain.
       | 
       | There are other valuable things, but IMHO the key is that, like
       | OO programming, they are valuable sometimes, not always. Being
       | explicit what is mutable and what can produces side effects is
       | really good, but forcing _everything_ to be immutable and without
       | side effects, is not.
       | 
       | So, while I like some things about functional programming, I'm
       | not a fan of pure functional programming. I'd rather have a
       | language that supports mixing multiple paradigms, even though
       | that means giving up some things that are avaliable only in pure
       | functional languages.
        
         | mrkeen wrote:
         | > I'm not a fan of pure functional programming
         | 
         | > Being explicit what is mutable and what can produces side
         | effects is really good
         | 
         |  _!!! That 's what Haskell is !!!_
         | 
         | What language are you using which is explicit about side
         | effects?
        
       | stevenalowe wrote:
       | interesting examples, but not compelling, i.e. procedural code to
       | do the same thing would also work (and might be easier to
       | understand for some).
       | 
       | the thing i loved about FP was the elimination of exception
       | handling
       | 
       | the thing i disliked about FP was how complex classes were
       | implemented as bizarre templates of structured list subtypes -
       | too much focus on the data types and structures of the
       | implementation, obscuring the domain-model (aka business) types
       | and structures required for human comprehension.
       | 
       | disclosure: scala, a few years ago
       | 
       | there is a happy medium...theoretically
        
       | twawaaay wrote:
       | I am a fan of mixing functional and object oriented (and also
       | some other paradigms).
       | 
       | Functional is great in cutting amount of repeatable code. It is
       | great for writing tools to process things regardless of their
       | exact type and for writing infrastructure code.
       | 
       | Object orientation is great when you want to model the domain of
       | the problem. Things that actually make sense when you are talking
       | to non-developers at your company. Clients, contracts,
       | appointments, employees, teams, invoices, things like that. But
       | when you start making objects that do not represent anything
       | meaningful you probably went a bit too far.
       | 
       | I think knowing various paradigms, knowing when to use which and
       | how to marry them together is critical for maintainable
       | implementations.
        
       | AtNightWeCode wrote:
       | The science says the math approach to programming is wrong. That
       | is why the langs with very little need of understanding of math
       | are the popular ones. It's the langs where people can be more
       | productive and more easily be able to do things like code
       | reviews. The topic is just silly.
        
       | teg4n_ wrote:
       | Never go full FP in JavaScript. I had a tech lead try to reinvent
       | Haskell in JavaScript and everyone else in the team had such a
       | difficult time dealing with their code it was ignored as often as
       | possible. When you start seeing shit like a "blackbird" function
       | to compose some other functions and you have absolutely no clue
       | wtf the point of it even after reading the source and genuinely
       | trying to understand you start to feel stupid and a bit resentful
       | lmao.
        
       | Waterluvian wrote:
       | I'm a fan of pure programming because of its predictability and
       | testability. And I'm a fan of chaining array functions to make a
       | data processing pipeline obvious. I like how these can be opt-in
       | and don't require a totally different
       | paradigm/language/architecture.
       | 
       | I'm guessing this may be seen as a part of FP but not the core?
        
       | [deleted]
        
       | adamwk wrote:
       | I wonder if the return of value semantics in languages lessens
       | the appeal of FP. Localized mutation lets you manage side-effects
       | but you don't need to bring in an esoteric discipline of math to
       | harness it.
        
         | mrkeen wrote:
         | How do you know if you're doing localised mutation?
         | 
         | Rust and Haskell are the only languages I know which help with
         | this.
        
           | adamwk wrote:
           | I was thinking of Rust, yes, but also Swift which has less
           | restrictions on ownership but still requires exclusive access
           | to modifying variables
        
       ___________________________________________________________________
       (page generated 2022-11-16 23:00 UTC)