Live data from Hacker News

Why I Prefer Functional Programming

morgenthum.dev

31–40 of 163 posts

Re: Why I Prefer Functional Programming

#31

I think this most effectively demonstrates why I like a lot of OOP: it can be verbose. This is example function is relatively illegible: alignCenter :: [String] -> [String] alignCenter xs = map (\x -> replicate (div (n - length x) 2) ' ' ++ x) xs where n = maximum (map length xs) One of the most verbose languages I've used, Objective C, has made this a best practice. Despite the brackets (which scare people off), it…

I'm finding that in Javascript, I really enjoy map() and filter(), but map() caused some friction on code reviews at one place, from someone I don't think had any FP background. The are best when they are one liners, of the form .map((val) => someFunction(val)) or .filter((val) => val.length > 1)

reduce() on the other hand is always illegible to me. I get pretty grumpy when I am 'forced' to use a reduce because the code calls for it. It just looks like I'm trying to write obfuscated code.

Often I'll just unroll it to a forEach.

This code structure in your example reminds me of some Python code I was reading recently (Norvig's Sudoku solver). Putting the conditional at the end of the line fights the way humans process data. Quite often we are trying to filter lines of code that could be involved in a problem and saying things like "do an action (if this condition is true)" increases the amount of short term memory I have to use to process the function. That's bad ergonomics.

Re: Why I Prefer Functional Programming

#32

I think this most effectively demonstrates why I like a lot of OOP: it can be verbose. This is example function is relatively illegible: alignCenter :: [String] -> [String] alignCenter xs = map (\x -> replicate (div (n - length x) 2) ' ' ++ x) xs where n = maximum (map length xs) One of the most verbose languages I've used, Objective C, has made this a best practice. Despite the brackets (which scare people off), it…

TXR Lisp:

  (defun align-center (strings)
    (let* ((maxl (find-max [mapcar len strings])))
      (mapcar (op fmt "~^*a" maxl) strings)))

Re: Why I Prefer Functional Programming

#33

I think this most effectively demonstrates why I like a lot of OOP: it can be verbose. This is example function is relatively illegible: alignCenter :: [String] -> [String] alignCenter xs = map (\x -> replicate (div (n - length x) 2) ' ' ++ x) xs where n = maximum (map length xs) One of the most verbose languages I've used, Objective C, has made this a best practice. Despite the brackets (which scare people off), it…

This opinion is flameworthy and stereotypes heavily: what seems to happen in FP is that the overall community is substantially math-IQ smarter than the imperative languages. Alas, that ALSO means the overall community loses social-IQ in the process.

This leads to:

1) higher barrier to entry for the general programmers, in language semantics, documentation, examples...

2) a tendency to overabstract, underdocument, and write clever code

3) write code that is obvious to the person who wrote it (at least for a few months), but being CODE is tougher for people to unpack.

4) people don't collaborate in packages, so they tend to be single-hero projects that are abandoned, and since FP code is a bit harder to parse for typical programmers, don't get adopted/unorphaned. Thus the library code beyond the standard library gradually degrades.

5) I won't say that FP is the only domain of religious zealotry in language minutae (syntax, etc), but it does seem to have a higher proportion or much louder zealots.

I've been in the industry for 30 years, and while it could just be mental ossification of age, nothing seems to have changed since the usenet days with Scheme/LISP, despite the fact the toolchains are now free and downloadable, and despite some of the smartest people in the world preferring them.

The fact that Rust is gaining some momentum with its fairly alien memory management is yet another example to me that the IQ barrier of purer FP (no infix, lots of recursion, etc) is just too high to surmount.

Re: Why I Prefer Functional Programming

#34

I think this most effectively demonstrates why I like a lot of OOP: it can be verbose. This is example function is relatively illegible: alignCenter :: [String] -> [String] alignCenter xs = map (\x -> replicate (div (n - length x) 2) ' ' ++ x) xs where n = maximum (map length xs) One of the most verbose languages I've used, Objective C, has made this a best practice. Despite the brackets (which scare people off), it…

A list comprehension in python would be more comprehensible than either AND less verbose.

Re: Why I Prefer Functional Programming

#35

Earlier quoted context omitted.

Once you become used to reading it, it doesn't seem like a big deal. But Haskell has a steep learning curve if you have never used functional programming languages before so it may take a while to pick up a few things.

What are some of the better ones to start with? I've tried Erlang and F#, but the hardest part is figuring out whether I'm writing code that's too procedural.

If you're looking for statically typed FP, honestly, start with Elm. You can do it in a weekend it's so conceptually contained. Then F# and OCaml are highly regarded. Avoid Haskell - worst bang for your buck on seeing returns on learning. It has some interesting concepts, but is a terrible language for learning statically typed functional programming.

If you're looking for dynamically typed FP (ex. LISP), go with Clojure, or lesser rec possibly Racket flavor of Scheme.

Re: Why I Prefer Functional Programming

#36
post #9

I started programming (like a lot of people) after I bought one of those "Learn C++ FAST!" books (I don't remember the actual title). A large chunk of this book was about the object-oriented part of C++, and comparing it to the equivalent version in C, and acted that since the only two paradigms that exist are OOP and imperative, you should always use OOP. (NOTE: I'm paraphrasing, that was the tl;dr as I remember it…

> I do really hate the type systems of Java and C++ because I think they're restrictive

Can you give an example of how the C++ type system restricts you? Is it just lack of some inbuilt mechanisms/syntactic sugars or is there something that you can't actually model with it?

> I think that forces strong and unnecessary coupling

How do you model/maintain invariants of a set of data in FP? That's the part that I don't understand yet.

Re: Why I Prefer Functional Programming

#37
post #14

I still don't get the point of immutability. Sure state change is a problem. How about a log like data structure that stores all modifications of the data? I'm sticking to procedural coding for the next 10 years and I will try my best to unwash young coders from poop.

That seems like an implementation detail. If you have an append-only log, you can always rely on each entry to never change. That's a kind of immutability. If you hold on to a reference to the log at a particular time, it will never change out from under you.

Re: Why I Prefer Functional Programming

#38
post #21

What I dislike about functional programming is that when objects are not supported or they are avoided I have seen poorly documented and complex hashes/collections data structures that end up reinventing the oop wheel (and the problem the wheel was solving in the first place). It feels like a false choice and you can have rich FP capabilities in a language that supports objects and relationships between objects.

Then you should look into Scala

[deleted]

Re: Why I Prefer Functional Programming

#39

I think this most effectively demonstrates why I like a lot of OOP: it can be verbose. This is example function is relatively illegible: alignCenter :: [String] -> [String] alignCenter xs = map (\x -> replicate (div (n - length x) 2) ' ' ++ x) xs where n = maximum (map length xs) One of the most verbose languages I've used, Objective C, has made this a best practice. Despite the brackets (which scare people off), it…

> I think this most effectively demonstrates why I like a lot of OOP: it can be verbose.

Verbosity is not inherently good. In fact, I think verbosity is inherently bad. Have you read much first-year programmer code? It's absurdly verbose at the cost of legibility.

The real issue is clarity. Your code should be sufficiently verbose that its purpose is self-evident, but it should not be overly verbose such that your screen is cluttered with meaningless junk (see: Java).

---

To me, there is a fundamental distinction between the intents of functional programming and imperative programming that a lot of these articles either gloss over or miss completely.

Imperative programming is about describing to the computer a procedure by which to accomplish a goal.

Functional programming is about manipulating the relationships between data directly such that you transform your given input into the desired output.

If you want to understand what a program does, then imperative code is going to be better to read. But if you want to understand what a program means, then (well-written) functional code is going to be better. This is also why so many functional languages have strong static type systems: to better enable the programmer to express programs' meanings outside of the implementation.

However, as others have mentioned, string manipulation is always kind of hairy anyway, so reading this function will result in understanding what it does instead of what it means (unless you just read the signature, which is actually what I do a lot of the time). My thought process of reading this particular function without prior context would be something like:

- The function is named `alignCenter` and takes a list of strings and gives back a list of strings... so the strings are being centered amongst themselves. I know they aren't being centered relative to anything else because there are no other inputs to the function — which I would not know in an imperative language, where there could be hidden state somewhere. - It maps some function over the list of strings. I assume that function will do the centering. - This inner function takes a string and does something to it. Let's investigate. - We replicate a space character some number of times and prepend the resulting string to the input string. (I think the author's reliance on operator precedence is disappointing here, as it detracts from the clarity IMO. I would rather put the `replicate` call in parens before the `++`.) - The number of spaces is determined by dividing by two some other number less the length of the string. - That number is the length of the longest string.

So: to center a list of strings, we indent each string by half the difference between its length and the maximum length among all the strings. This seems like a reasonable way to center a group of strings. (Notice that I did not use words like "first", "then", etc. which indicate a procedure. Instead, I have described the relationships of the strings.)

(Of course writing it all out makes it seem like a longer process than it is, but in reality it probably took me 10-15 seconds to go through everything and figure out what was going on.)

---

I think this isn't a great example for the author to have chosen. My go-to example of a beautiful functional solution is generating the Fibonacci sequence.

A "good" imperative solution uses iteration and might look like:

    def fib(n: int) -> int:
      a = 0
      b = 1
      while n > 1:
        t = a
        a = b
        b = t + b
        n -= 1
      return b
If you were to just glance at this code without being told what it does (and if you'd never seen this particular implementation of the algorithm before), you would probably need to write out a couple test cases.

Now, the Haskell solution:

    fib :: Int -> Int
    fib n = fibs !! n
      where fibs = 0 : 1 : (zipWith (+) fibs (tail fibs))
We can easily see that the `fib n` function simply retrieves the nth element of some `fibs` list. And that list? Well it's `[0, 1, something]`, and that something is the result of zipping\* this list with its own tail\* using addition — which very literally means that each element is the result of adding the two elements before it. The Fibonacci numbers are naturally defined recursively, so it makes sense that our solution uses a recursive reference in its implementation.

\*Of course, I'm assuming the reader knows what it means to "zip" two lists together (creating a list by performing some operation over the other two lists pairwise) and what a "tail" of a list is (the sub-list that simply omits the first element).

To me, this data-relationship thing often makes more sense than a well-implemented imperative solution. I don't care to explain to a computer how to do its job; I care to think about how to move data around, and that's what functional programming is all about (to me).

Of course, this is just my subjective opinion, but I think there's some merit to it. I'd like to hear your thoughts!

Re: Why I Prefer Functional Programming

#40

I think this most effectively demonstrates why I like a lot of OOP: it can be verbose. This is example function is relatively illegible: alignCenter :: [String] -> [String] alignCenter xs = map (\x -> replicate (div (n - length x) 2) ' ' ++ x) xs where n = maximum (map length xs) One of the most verbose languages I've used, Objective C, has made this a best practice. Despite the brackets (which scare people off), it…

I think this is a question that's orthogonal to OOP-versus-functional-programming, but is rather about programming style. Haskell programmers like being terse, but there's also nothing stopping you from writing Haskell like this: alignCenter :: [String] -> [String] alignCenter lines = let maxLineLength = maximum (map length lines) in [ leftPadding ++ line | line You could have verbose and easy-to-read functional code…

Functional programming seems to let people lapse into "point-free style" fairly easily, which (imho) has a much greater chance of becoming rapidly unreadable. Not to say FP can't be readable as you've demonstrated very well.

https://en.wikipedia.org/wiki/Tacit_programming

Post reply on HN