11 ms·
Cute. All kidding aside, though, functional programming is worth the effort to learn, and it doesn't actually take 15 years. The payoff is at the end of the art
by munchler 2y ago
Cute. All kidding aside, though, functional programming is worth the effort to learn, and it doesn't actually take 15 years. The payoff is at the end of the article:
"It’s quite natural to program in Haskell by building a declarative model of your domain data, writing pure functions over that data, and interacting with the real world at the program’s boundaries. That’s my favorite way to work, Haskell or not."
Haskell can be intimidating, though, so I would recommend F# for most beginners. It supports OOP and doesn't require every single function to be pure, so the learning curve is less intense, but you end up absorbing the same lesson as above.
- initplus 2y agoYes - the value of functional programming isn't that working in OCAML, or F#, or Haskell is 10x as productive as other languages. But that it can teach you worthwhile lessens about designing software that apply equally to imperative languages. Modelling the business domain, reasoning and managing side effects, avoiding common imperative bugs, these are all valuable skills to develop. F# is a great language to learn, and very approachable. Worst part about it is interacting with antiquated .NET API's. (I can't believe the state that .NET support for common serialization formats is still in...)
- sidkshatriya 2y ago> Yes - the value of functional programming isn't that working in OCAML, or F#, or Haskell is 10x as productive as other languages. This is not true in my personal experience. As has been famously said (paraphrased): Functional programming makes tough problems easy and easy problems tough. In other words the value of functional programming depends on your domain.
- NinoScript 2y agoSo you’re saying that it does make you 10x as productive?
- initplus 2y agoMaybe my phrasing is not clear - I meant that these languages are indeed not significantly more productive.
- marcosdumay 2y agoBut (and I agree with the GP) they are. They are overwhelmingly more productive, in a way that you often can't even compare quantitatively. They are also a lot less productive. It depends entirely on what you are doing.
- grumpyprole 2y agoBy what measure? Haskell can be a huge productivity multiplier. The standard library is built upon many powerful, unifying and consistent mathematical abstractions. For example, there is almost no boilerplate to write for any traversal, mapping, error handling etc. The average Pythonista simply has no idea what they are missing. But Haskell doesn't have anywhere near the third party ecosystem of Python, so is less productive by some measures.
- antonvs 2y ago> easy problems tough. That needs a qualifier: it can make easy problems tough if you're not familiar with how to solve them in a functional context. A big part of that is because smart people have already solved the tough problems and made them available as language features or libraries.
- jiggawatts 2y agoAbsolutely! Any beginner can readily combine the catamorphisms and anamorphisms in `recursion-schemes`, or use the ready-made hylomorphisms for common tasks such as setting a value in a data structure. What could be simpler? /s https://wiki.haskell.org/Zygohistomorphic_prepromorphisms https://wiki.haskell.org/Zygohistomorphic_prepromorphisms
- amoss 2y agoThey have played us for absolute fools.
- cubefox 2y ago> That needs a qualifier: it can make easy problems tough if you're not familiar with how to solve them in a functional context. All problems are easy if you are familiar with how to solve them. Unfortunately it's part of the problem to find out how to solve them, and that can be unusually hard in case of functional programming. Like solving something with recursion instead of loops + states. There is a reason cookbooks use loops not recursion.
- simiones 2y agoNot really, certain problems are just inherently harder to express in a purely functional way than they are in an imperative way (and the reverse is just as true). For example, computing a histogram is much simpler in imperative terms (keep an array of histogram values, go through the original list, add 1 to the array element corresponding to the current element in this list) than in a purely functional style, especially if you need a somewhat efficient implementation. My favorite example of this is implementing quicksort. It's significantly easier in C than it is in Haskell.
- kreyenborgi 2y ago> makes tough problems easy and easy problems tough And because of mutual recursion, that means that tough is easy (and easy tough). In other words, if we call the class of tough problems T and easy problems NT, we have T==NT, given FP.
- williamcotton 2y agoWhat easy problems are tough in F#? I’ve been using it for writing random scripts and as a Python replacement.
- z500 2y agoWriting recursive descent parsers in F# is a lot of fun with ADTs and pattern matching.
- DimmieMan 2y agoIt's an overgeneralisation. If you try and turn F# into Haskell at home you may run into that problem. F# is functional first language so if an object oriented or procedural solution is the right call the options right there when you need it.
- chrischen 2y agoIt’s only tough to change your way of thinking. Most people making the switch find it tough because they are trying to find imperative techniques to do something in a functional way and struggling because they can’t find an if else statement or a for loop. But if you were never taught to think in terms of conditional branching or looping indexes you’ll save a lot of time.
- theCodeStig 2y agoExactly. I've long held the sentiment, that pure functional programming is easier than imperative programming. The only hard part, is switching from an imperative mindset.
- pyuser583 2y agoHow do you “Hello World” in a functional language? Doesn’t it have side effects?
- sevensor 2y agoThere's some real confusion about what "functional" means, because it depends on who's speaking. Writing _exclusively_ pure functions is a Haskell thing. A much looser definition of the functional style would be to say that you mostly write pure functions over immutable data, but when you have to actually do a side effect you write a procedure that talks to the outside world and go on with your day. If you go digging in this site's archives from about ten years ago, I recall numerous debates about what constituted functional programming, and whether the latter counts at all. But if we _are_ talking about Haskell, the answer to your question is obviously "Monads."
- cess11 2y agoThe string "Hello World" evaluates to itself, what else do you need? Edit: Eh, I thought it was a fun quip.
- trealira 2y agoYes, and AFAIK, you're pretty much free to cause side-effects in functional languages; it's just a bit awkward and somewhat discouraged. It's kind of like how C still has goto, yet it's still a structured programming language. Even in Haskell, which tries to control side-effects more, it's not hard; it's just that it's stuck with an "IO" annotation. Any function that calls an IO function also becomes an IO function; it's infectious. main :: IO () main = putStrLn "hello, world"
- 2y ago
- deleted 2y ago[deleted]
- wruza 2y agoHot take of the day: you learn that with imperative programming just as well. I familiarized myself with fp to the point of writing scheme and haskell around 15 years ago. Read the classics, understood advanced typing, lambda calculus and so on. The best “fp” I’m using nowadays is closures, currying in the form of func.bind(this[, first]) and map/filter. Which all are absolutely learnable by the means of closures, which are useful but I can live without. Sometimes not having these makes you write effing code instead of fiddling with its forms for hours. Still waiting for the returns from arcane fp-like code I produced earlier. Cannot recognize nor understand none of my projects in this style that I bothered to save in vcs. Imperative code reads like prose, I have some of it still in production since 2010. These FP talks are disguised elitism imo (not necessarily bad faith). Beta reduction and monadic transformers sound so cool, but that’s it job-wise.
- cubefox 2y ago> These FP talks are disguised elitism imo (not necessarily bad faith). Beta reduction and monadic transformers sound so cool, but that’s it job-wise. They may be disguised mathematics. People are into math because it is neat / elegant / cool. So they study it regardless of whether it has a practical use or not.
- photonthug 2y agoSome programmers have serious math envy. This can be good if they are self aware about it and keep it in check, because it makes them better programmers. Otherwise they can a pain to work with. Seniors should be people that have dealt with this aspect of their own talent, not juniors who are promoted in spite of or because of it
- dboreham 2y agoMathematics is just a kind of programming. And vice versa.
- cubefox 2y agoPrograms fundamentally have state, while mathematical equations have not. Math is in its core declarative, while programming is essentially imperative, at least under the hood.
- baby 2y agoOcaml definitely doesn’t make you more productive
- DimmieMan 2y agoI wouldn't even say antiquated, modern .Net APIs can suck to work with too, the entire ecosystem is written for C# ASP.Net core and everything else feels second class. I love F#, the working with C# elements of the language drove me away.
- neonsunset 2y agoWhich elements were the source of pain? Writing web applications and back-ends in F#, as far as I'm aware, is straightforward and a joy because of integration with the rest of ecosystem.
- nequo 2y agoThat’s interesting because F#’s OOP, as someone who knows neither C# nor Java, makes it more intimidating to me than OCaml. Also interesting that when FP is mentioned, Hindley-Milner is implicitly understood to be part of FP too even though it doesn’t have to be. Clojure emphasizes immutability and FP but with dynamic typing and everything that comes with that.
- mrkeen 2y ago> Clojure emphasizes immutability Is "emphasizes" just another word for second-class support? C++ emphasizes the importance of memory safety.
- y1n0 2y agoImmutability is definitely first class in clojure, but you can work with mutable structures when you need to.
- mrkeen 2y agoThis is sounds like memory safety in C++. https://www.infoworld.com/article/3714401/c-plus-plus-creator-rebuts-white-house-warning.html https://www.infoworld.com/article/3714401/c-plus-plus-creato...
- nequo 2y agoThis seems like a meaningless criticism when it comes to immutability in Clojure. You can have mutability in Haskell too. That doesn’t make it as unsafe as memory management in C++.
- mrkeen 2y ago> You can have mutability in Haskell too. Haskell enforces this via a type system. What safeguards around mutability does Clojure have? If I import a method 'foo()', is there any kind of contract, notation ... anything which could suggest whether it mutates or not?
- __rito__ 2y agoFor the benefit(s) that you list, which are the best learning resources for F#?
- neonsunset 2y agohttps://fsharpforfunandprofit.com/ https://fsharpforfunandprofit.com/
- richrichie 2y agoBut why do we need Haskell for this?
- anon291 2y agoRealistically we don't but it's very rare to meet a programmer who understands these distinctions thats not also a great functional programmer. This is my experience after spending five years as a Haskell programmer and managing a Haskell team for several years and now moving back to the c++ world to play with AI. I know lots of good c++ programmers working on cutting edge stuff, real experts in their field, but they sometimes still don't have a clear way to understand how to model data That is my opinion. It's probably highly contentious.
- cornel_io 2y agoI've actually had to fire a technically exceptional Haskell programmer because of the damage they did to our C# codebase (and arguably moreso, the team). Sometimes it's not a matter of talent or skill, but culture fit. In my experience FP-aligned people on non-FP projects tend to be more likely to overengineer, more prone to argue in favor of the Great Rewrite For No Reason Except Aesthetics, and more likely to abuse "lesser" programmers when they put up PRs. They suck as team players on teams that are not made of language nerds. I am not just talking about the one person here who I fired, this is a legit pattern I've noticed over at least a half dozen people. Conversely, they are exactly the right people to deploy when you have really tough, self-contained problems to solve that you wouldn't trust the normal Java 9-5ers to tackle. No matter how they do it, you can always rewrite their working code in a more maintainable language later once it's working, and make it integrate well with the rest of your stack. :D
- MrBuddyCasino 2y agoThis is my experience, too. Some of the worst code I‘ve seen was a Haskell guy who first built his own (reactive?) concurrency framework and then implemented the actual functionality in completely unidiomatic and undocumented Java. Some people don’t understand that the „best solution“ is not necessarily equal to the most beautiful abstraction they can think of.
- beders 2y agoI feel the same pay-off - but arrived at that point via Clojure. Immutable-first, aim for purity, ability to drop out of it when necessary. As stringent as you need it to be (static vs. dynamic types vs. specs), as flexible as you want it to be.
- IshKebab 2y agoI feel like functional programming is pretty trivial. It's pure programming that is very difficult. They're often conflated because Haskell is pure and functional and probably the most talked about heavily functional language. I certainly didn't know that impure functional languages like OCaml existed for ages.
- fire_lake 2y agoIs Haskell pure? It has exceptions You can divide by zero It has unsafe IO primitives
- tome 2y agoYou're right: "pure" is not a well-defined concept. The well-defined concept that describes Haskell's benefits in this regard is "referential transparency". That means that this code let x = <definition of x> in ... x ... x ... (i.e. defining a variable x and then using it some number of times) is equivalent to ... <definition of x> ... <definition of x> ... Seen in the opposite direction (transforming the bottom code to the top code) this means that extracting repeated code is always a valid thing to do. It's not valid in most other languages, and certainly no mainstream ones.
- simiones 2y agoWell, technically that isn't true if you use, for example, unsafePerfomIO in the defintion of x. Referential transparency is still a spectrum, just like purity. Haskell is much closer to purity than the vast majority of languages out there. Also, even if Haskell were perfectly pure, the fact that it uses lazy evaluation is far more important to actually being able to make use of referential transparency. In a strict language you will still see a massive performance differences if replacing the first version with the second, in the most common cases.
- tome 2y ago> technically that isn't true if you use, for example, unsafePerfomIO in the defintion of x Ah, well, regardless of whether it holds in Haskell, referential transparency is a well-defined concept. Purity is not a well-defined concept (at least as far as I know. Please share a formal definition if you have one!). That's primarily what I'm trying to say. But I also disagree with your point about unsafePerformIO. In practice, nothing in Haskell violates referential transparency in a significant way. Who knows why? It's an emergent phenomenon that in principle need not have occurred, but in practice it did. Debug.Trace and similar are about the only things that technically violate referential transparency (and they are extremely tame). > the fact that it uses lazy evaluation is far more important to actually being able to make use of referential transparency Yes, I agree with that.
- realPtolemy 2y agoOr Elixir! Quite easy to grasp as well.
- dejvid123 2y agoI would suggest Scala as FP for beginners. It doesnt forces you to do pure functions. And its really beginners friendly to start with.
- empath75 2y agoI was a college dropout and self taught bash and python programmer and quite some time ago, I read about Haskell, decided to teach myself to use it, and then realized I had absolutely no idea what programming actually was, and basically spent the next 15 years teaching myself computer science, category theory, abstract algebra and so on, so that I could finally understand Haskell code. I still don't understand Haskell, but it did help me learn Rust when I decided to learn that. And I think I could explain what a monad is. edit: It's a data structure that implements flat map. Hope this saves someone else a few years of their life.
- bspammer 2y agoI think that's a good starting definition for programmers, but still could cause confusion when you run into something like IO in Haskell. IO isn't really a data structure, and it's hard to fit the "flat map" concept to it.
- nextaccountic 2y agoIf you want you can still keep this point of view, by saying that IO is conceptually a data structure that builds a description of what the program does. In this point of view it follows that there is another, impure program that interprets the IO data structure and actually performs the computations (Of course in practice IO isn't implemented like this, because it would be too slow) (But in every other language, like Javascript or Python, you can define IO as a data structure. Or even in Haskell itself, you can define for eg. a free monad that gets interpreted later, and it can be made to be just as good as IO itself, though typically people make it less powerful than IO) However note that every other "computational" monad (like the list monad or the Cont monad) actually is a data structure, even though they describe effects just like IO does. This is because IO is the only possible exception to the "monads are data structures" thing in Haskell (if you don't subscribe to the above view), because Haskell doesn't let you define types that aren't data structures The only issue with this point of view is that you now need to say what flatMap means for things that are not shaped like arrays. Eg. does it make intuitive sense to flatMap a tree? (A retort is that it must make sense, whatever you call this operation; and flattening a tree means to turn a tree of trees into an one-level tree)
- crabbone 2y agoI would recommend neither of those. Haskell has very bad syntax (with extensive backing from Microsoft, iirc the guy who writes the compiler is a Microsoft's Research employee). F# is a straight-up Microsoft's language. It doesn't matter what other benefits it has. Just don't touch anything created by that company, and you will have one fewer regrets in your life. But, if you still want a language from that category: SML or Erlang would be my pick.
- fransje26 2y ago> Just don't touch anything created by that company, and you will have one fewer regrets in your life. :-)
- square_usual 2y agoSPJ has left MSR and is now at Epic games, working on a new PL. However, even while he was at MSR, MS didn't really have a say in how Haskell was developed.
- crabbone 2y agoWell, MS didn't have to do anything. It's enough that they have (or had) the opportunity to do something. There isn't an Overmind in MS that in a creepy voice tells you to spawn more overlords. Less than that, there doesn't need to be a written document that tells you to give money to MS or your data etc. There's just a general accepted understanding among the people who run that company that ends justify the means. And by "ends" they mean them and their investors getting rich. If Haskell compiler could've been turned into a money-making machine, and it only required killing off half of Haskell programmer, MS would be working overtime on the plan to hide the bodies, but they'd never even consider the possibility of killing being bad... (metaphorically speaking, hopefully)
- nequo 2y agoDo you also suspect homicidal money making motives behind Z3, Lean, and F*? It seems more likely to me that they just want some useful knowledge out of these projects that they can integrate into a product that actually sells.
- czhu12 2y ago> doesn't require every single function to be pure having never done F# or haskell, doesn't that start getting into the territory of languages that encourage functional programming like ruby or javascript (modern javascript)?
- Bostonian 2y agoIn modern Fortran, functions should be pure (although the language does not require this), and procedures that mutate arguments are made subroutines (which do not have return values).
- pklausler 2y agoNote that Fortran's interpretation of the term "pure" bizarrely allows a "pure" subprogram to depend on mutable state elsewhere (in a host, a module, or a COMMON block). So Fortran's "pure" functions aren't referentially transparent. (F'2023 added a stronger form of "pure" and calls it "simple", but it didn't strengthen the places where a "pure" procedure should be required to be "simple", such as DO CONCURRENT, so being "simple" will be its own reward, if any compiler actually implements it. And a "simple" function's result value can still depend on a mutable pointer target.)
- sterlind 2y agoI really wanted to like F#, and I kinda do, but it has a number of quirks, compiler issues and cracks in the design that are getting worse: First off, the compiler is single-pass. All your definitions have to be in order. This even extends to type hints - it can't use clues to the right to deduce the type of an expression on the left. This is supposedly for perf reasons, but the compiler can become extremely slow because the inference engine has to work so hard - slower than GHC for sure. Speaking of slowness, Haskell is surprisingly fast. Idiomatic Haskell can be within 50% the perf of C, since its laziness and purity unlock powerful optimizations. F# is eager and the compiler doesn't do anything fancy. Perf often makes you reach for mutable state and imperative structure, which is disappointing. The OOP paradigm feels bolted on. Should you use classes or modules? Pure functions or members? It depends, what mood are you in? Unfortunately only member functions support overloads, and overloads are useful for some SFINAE-type patterns with `inline` functions, so they get a bit overused. `ref` struct support, which is vital for zero-copy and efficient immutable data, have very primitive support. even C# is ahead on this. Very limited support for implicit conversions, no support for type classes and no function overloading leaves F# with nothing like a numeric tower you'd have in Lisp, and makes building something like Numpy clunky. I use C# at work, and I love Haskell, so I really wanted to love F#. But it just doesn't get the love it needs from MS, and some design decisions aren't aging well - particularly as C# itself evolves in directions that are tricky for F#'s aging compiler to support.