6 ms·
> Now that (nearly) every mainstream language has lambda expressions, there are very few patterns in functional programming that cannot be replicated in mainstr
by noelwelsh 4y ago
> Now that (nearly) every mainstream language has lambda expressions, there are very few patterns in functional programming that cannot be replicated in mainstream languages
I don't think this is true. Algebraic data types and exhaustive pattern matching, which implies a type system, are the things I use most in my adventures in functional programming. Mainstream languages (for some definition of mainstream) don't yet have these features.
The original post doesn't mention pure FP. I don't think purity is that interesting when you can have a type system that can reason about mutation (i.e. linear or affine types, similar to Rust.)
- lolinder 4y agoKotlin and Java now have sealed classes/interfaces, which can provide exhaustive pattern matching and as far as I can tell can be used to model any ADT. EDIT: In fact, both languages are now listed as having ADTs on the Wikipedia page: https://en.m.wikipedia.org/wiki/Algebraic_data_type https://en.m.wikipedia.org/wiki/Algebraic_data_type Also, TypeScript's union types can express ADTs, and Rust's enums. I don't think it will be very long before the rest of the mainstream languages catch up.
- noelwelsh 4y agoAgreed, but that's why I hedged with "some definition of mainstream". I don't think Kotlin or Rust are mainstream yet, most Java places are still on Java 8 or 11, and ADTs in Typescript are a PITA.
- kaba0 4y agoI wouldn’t be surprised if there would be more people on Java 19 than on Haskell, for what it’s worth.
- wk_end 4y agoADT's in TypeScript aren't as nice as in a language that supports them natively in many respects, but "PITA" is really overselling it. We use them pervasively at my shop. In fact, the ability to synthesize them without naming them (because TypeScript is structurally-typed instead of nominally) sometimes makes them even more convenient than in most FP languages (OCaml excepted) - the ability to, say, return an ad-hoc ADT from a lambda without giving it some meaningless name like "HelperFunctionResult" can occasionally be really handy.
- nerdponx 4y agoIt's also a matter of performance. Functional non-mutating patterns in JavaScript and Python can be substantially, sometimes catastrophically, less performant than the procedural/imperative mutating equivalents. All functional programming languages that I know of which have decent performance rely on an optimizing compiler to some extent, and/or core data structures that have been optimized for immutability.
- smitty1e 4y agoPython bogs down where there is excess use of the dynamic aspects, e.g., a large list comprehension. Go with a generator, and watch that list be more kind to the resources.
- chaorace 4y agoThe thing that really irks me is that the generator pattern doesn't have to be an OO-first feature. Observable streams[1] work with the same basic foundation and those are awesome for FP. It's really frustrating that standard libraries are so eager to adopt generators without taking that last step into supporting functional stream consumption. [1]: https://reactivex.io/ https://reactivex.io/
- nerdponx 4y ago> Python bogs down where there is excess use of the dynamic aspects, e.g., a large list comprehension. Go with a generator, and watch that list be more kind to the resources. This is a micro-optimization and it's not always true. Generators usually use less memory, but list comprehensions can actually be faster because the memory gets allocated all at once and the loop is performed internally inside the interpreter, instead of the generator possibly being consumed as a slow top-level loop. I was talking about examples like making a copy of a list/dict/object instead of replacing elements in-place, or using a stack of map/filter operations instead of a single-pass for-loop with dynamic programming.
- smitty1e 4y agoFair point, especially in the case of network-bound or disk-IO intensive work.
- bryanlarsen 4y agoADT's and exhaustive pattern matching are in Rust. The way you wrote your comment makes it clear that you know that, but might as well make it explicit. IMO, people come to Rust because of memory safety, but they stay because of ADT's and similar features.
- adastra22 4y agoAlgebraic data types and exhaustive pattern matching Are a core part of Rust.
- shpongled 4y agoRust, but practically no other mainstream or OO/imperative style language
- adamwk 4y agoSwift, kotlin, Java
- haspok 4y agoThere is no proper pattern matching / destructuring in either Java or Kotlin. There is a discussion about it in Kotlin, see https://youtrack.jetbrains.com/issue/KT-186/Support-pattern-matching-with-complex-patterns https://youtrack.jetbrains.com/issue/KT-186/Support-pattern-...
- pxc 4y agoalso Scala, which I'd take over Java any day
- docandrew 4y agoAda might be getting pattern matching soon too: https://github.com/AdaCore/ada-spark-rfcs/blob/master/prototyped/rfc-pattern-matching.rst https://github.com/AdaCore/ada-spark-rfcs/blob/master/protot...
- kilgnad 4y agoRust has ADTs and it has exhaustive pattern matching AND it's not functional. It's arguably mainstream now. Haskell doesn't have exhaustive pattern matching it just gives you a warning.
- ParetoOptimal 4y ago> Haskell doesn't have exhaustive pattern matching it just gives you a warning. It can have exhaustive pattern matching if you use `-Werror`. That's frequently the default in an industrial Haskell setting. I wish that non-exhaustive patterns would be an error by default though.