5 ms·
Fifteen years into my career, and I'm finally realizing that "expressive" languages are practically unreadable.
by pensatoio 1y ago
Fifteen years into my career, and I'm finally realizing that "expressive" languages are practically unreadable.
- tikhonj 1y agounfamiliar languages are practically unreadable
- rhdjsjebshjffn 1y agoI don't see how that's any better for a haskell shop. i got some empathy but you chose a rough life.
- yakshaving_jgt 1y agoThe trick is to hire people who are familiar with the language.
- rhdjsjebshjffn 1y ago[flagged]
- sponnath 1y agoNot all programming languages are obvious derivatives of C. Haskell is pretty readable once you spend some time getting to know the syntax.
- 90s_dev 1y agoThe semantics are very different. It's much closer to a mathematical proof than a C program with different syntax, in terms of its lazy evaluation.
- Darmani 1y agoI prefer to think of Haskell-like lazy evaluation as constructing a dataflow graph. The expression `map f (sort xs)` constructs a dataflow graph that streams each output of the sort function to `f`, and then printing the result begins running that job. Through that lens, the Haskell program is more like constructing a Spark pipeline. But you can also think of it as just sorting a list then transforming each element with a function. It only makes a difference in resource costs or when there's potential nontermination involved, unless you use unsafe effects (e.g.: unsafePerformIO). Is there a way to think of proofs as being lazy? Yes, but it's not what you think. It's an idea in proof theory called polarization. Some parts of a proof can be called positive or negative. Positive parts roughly correspond to strict, and negative roughly correspond to lazy. To explain a bit more: Suppose you want to prove all chess games terminate. You start by proving "There is no move in chess that increases the number of pieces on the board." This is a lemma with type `forall m: ChessMove, forall b: BoardState, numPieces b >= numPieces (applyMove m b)`. Suppose you now want to prove that, throughout a game of chess, the amount of material is decreasing. You would do this by inducting over the first lemma, which is essentially the same as using it in a recursive function that takes in a board state and a series of moves, and outputs a proof that the final state does not have more material than the initial state. This is compact, but intrinsically computational. But now you can imagine unrolling that recursive function and getting a different proof that the amount of material is always decreasing: simply write out every possible chess game and check. This is called "cut elimination." So you can see there's a sense in which every component of a proof is "executable," and you can see whether it executes in a strict or lazy manner. Implications ("If A, then B") are lazy. Conjuctions ("A and B") can be either strict or lazy, depending on how they're used. I'm at the edge of my depth here and can't explain more -- in honesty, I never truly grokked proof polarization. Conversely, in programming languages, it's not strictly accurate to say that the C program is strict and the Haskell program is lazy. In C, function definitions and macro expansions are lazy. You can have the BAR() macro create a #error, and yet FOO(BAR()) need not create a compile error. In Haskell, bang patterns, primitives like Int#, and the `seq` operator are all strict. So it's not the case that proofs are lazy and C is strict and Haskell is lazy so it's more like a proof. It's not even accurate to say that C is strict and Haskell is lazy. Within a proof, and within a C and a Haskell program, you can find lazy parts and strict parts.
- rrradical 1y agoAs a haskell programmer, all of that was easily readable.
- sgarland 1y agoAs a non-Haskell programmer, all of that was easily readable. Straightforward words for functions makes that pretty easy.
- RHSeeger 1y agoThere were a couple of places that took me a couple reads to figure out, like the fact that `(x:)` was "prepend". But overall, I followed the code pretty well. From the context of someone that wrote a small amount of Haskell a decade ago.
- StopDisinfo910 1y agoIt’s partial application of cons via the operator, admittedly a poor choice from Haskell, a language which likes operators a bit too much. I think eta-expansion makes the whole thing clearer: (\xs -> x:xs) but most Haskellers would disagree. The article also features examples of point-free style, another unfortunate trend for readability. As long as you use operators sparingly, don’t abuse partial application and prefer explicit lambdas to composition, Haskell is fairly readable. The issue is that approximately no Haskeller writes Haskell this way.
- deleted 1y ago[deleted]
- Skeime 1y agoI don't use Haskell nearly enough to call myself a Haskeller but I will still disagree. Yes, operator sections are yet another thing to learn but I find them very intuitive, and actually easier to read than the equivalent lambda expression because I don't have to match up the bound variable. (For example, (\x -> x ++ y) and (\y -> x ++ y) look pretty similar to me at first glance, but (++y) and (x++) are immediately distinguishable.) Of course, this is reliant on knowing the operators but that seems like a mostly orthogonal issue to me: You still need to know the operator in the lambda expression. That said, the niceness of sections gives people yet another reason to introduce operators for their stuff when arguably they already are too prevalent.
- bcrosby95 1y agoHow much time have you spent with functional programming languages?
- djtango 1y agoWe once hired a F# developer to write Clojure and within a week, he was writing some of the clearest Clojure I've read. Learn paradigms not languages...