What is it with functional languages and people naming their variables with single letters? If I wrote some python code like that I'd be laughed out of the room
Everyone I know who programs with single letters comes from a graduate-level math background. There seems to be a kind of belief that elegance and compactness are desirable.
Of course it’s the polar opposite of self-documenting, legible, understandable, easy-to-maintain code.
Academic notation is much less concerned with self-documentation and much more concerned with brevity and correctness.
I'm glad we never needed to learn these forms in school:
horizontalDisplacement = -(linearCoefficient +- sqrt(linearCoefficient^2 - 4 x quadraticCoefficient x constantCoefficient)) / (2 x quadraticCoefficient)
My first thought upon reading those was... my god, if that’s how I’d first learned it in 7th grade, it would have made so much more immediate, intuitive sense to me and the rest of the students!
We’re taught so many formulas where we don’t have the slightest intuitive idea of what the variables mean or the effect they have (unless we’re naturally really intuitively good at math, which only a very small proportion of students are).
But if they said it right in their name... that seriously would have been a game-changer for a lot of students, I think. A gigantic help for understanding how to connect formulas to practical word problems.
Fine, but that doesn't address the point GP is making. This is a subject near and dear to my heart, since I am constantly frustrated by the opaque nature of functional programming tutorials on the internet. Functional composition is very difficult for beginners to pick up, and using single letter variable names for everything significantly compounds that problem. There are many concepts in FP that can elevate the craft of software design, and it's a tragedy that a lack of approachable instructional materials convinces most programmers that either they are not smart enough to learn it, or that it's Ivory tower nonsense. Ease of readability is a virtue in any programming environment, and I personally feel that the FP community as a whole should make lowering the barriers to entry a top priority. I'm grateful to all of the people working hard to bring functional programming to the masses, but I have a sneaking suspicion that many functional programming practitioners like that it looks complex and difficult to outsiders. Just my two cents.
Just because I can't resist writing little math things in Haskell:
primes = 2 : filter isPrime [3..]
isPrime n =
let divisors = takeWhile (\d -> d * d <= n) primes
in not $ any (\d -> n `mod` d == 0) divisors
strongPrimes =
let primeTriples = zip3 primes (drop 1 primes) (drop 2 primes)
in [b | (a, b, c) <- primeTriples, b*2 > a + c]
For what it's worth, I've worked as a professional Haskell programmer at multiple companies and have been writing Haskell for more than a decade, and I still have trouble reading code written in that style. I usually end up decomposing it at a REPL so I can look at the types of intermediate parts of the program.
(In practice, most—although not all, admittedly—of the Haskell codebases I've worked with tended to be a lot less dense than the occasional combinator-heavy sample code you see in blog posts and comments.)
In fairness to Haskell, I didn't exactly go for readability in the above example, and indeed someone's already added a more readable example. I'll break it down for the sake of completeness:
scanr is a reduce function that produces a list of the reduction steps rather than just the final output. So I'm processing the list of primes and punting out (Maybe i, i i) at each stage (I could have included the type signature for "g" but I was deliberately going for a perl-like style.)
fst3 just takes the first element of a triple i.e. Maybe i. mapMaybe maps and throws away the "Nothing"s. Think of those as nulls.
So, returning to g, it returns a (Maybe i, i, i). The Maybe i is the prime if it's strong, Nothing if it isn't. The other two are the previous two primes. So what g does is a) compute the first element and b) copy the new prime (n) into the first location and the previous prime (p) into the second location.
"<$ guard" is a bit of a Stupid Dwarf Trick in all honesty, but the effect is: the expression on the right is a boolean expression. If it returns true, the expression on the left is returned. If it returns false, "Nothing" is returned.
If you are interested, I highly recommend working through this: https://www.cis.upenn.edu/~cis194/spring13/lectures.html
(and that means doing the exercises). Haskell's a funny language in that there's a fairly easy way of doing things that would read how you would expect, and a whole bunch of "oh, but this is more elegant" things you can add on top. Thankfully, some of the most cutting edge features like ApplyingVia are actually producing _more_ readable code, not less.
Have you tried working through a more structured learning process like Haskelbook? Once you get the basics, the types begin to add lots of clarity to what is going on in a function and make it easier and faster to comprehend complicated behavior.