HNHacker News
TopNewBestAskShowJobs

ebingdom

577 karma · joined May 5, 2021

submissionscomments
ebingdom··on A Linux distro with a focus on simplicity and the concept of less is more
That alternative definition seems less useful, because quite often there are two people who can individually maintain a project, and in that scenario the bus factor is 0 even though there is a risk that both of them will leave the project.
ebingdom··on Against SQL
By the "author", I meant the author of the article. I figured you were just being consistent with them.
ebingdom··on Against SQL
The author uses the term "union", but unfortunately they picked the one wrong term against a long list of correct alternatives: sum type, tagged union, discriminated union, coproduct, disjoint union, variant, algebraic data type, ...

"Union" does not imply disjointness (which is the source of many problems), whereas all those other terms do.

ebingdom··on Functools – The Power of Higher-Order Functions in Python
I'd much rather debug someone's pure functional code rather than trying to figure out how someone's imperative code got into some unexpected/invalid state.
ebingdom··on Functors and Monads for People Who Have Read Too Many “Tutorials”
> They want to geek out and feel smart.

Jesus Christ, I am so sick of you and all the people like you who repeat this lie. I've invested a lot of time learning about category theory, domain theory, type theory, etc. so I could become the best version of myself as a programmer, and I have seen very real benefit from this investment. Only to have you and these other people in HN tell me I'm just trying to "feel smart". Your arrogance is so off-putting to me.

When did HN become so anti-intellectual? If you don't understand something, then either learn it or don't—but you don't need to bash other people for their own efforts.

ebingdom··on Functors and Monads for People Who Have Read Too Many “Tutorials”
> generally favour hard to understand style like point free where pipes are a lot easier to follow

No they don't. Every Haskeller I know (myself included) acknowledges that sometimes point free style is better, and sometimes it isn't. None of them would unilaterally declare it better, and most generally avoid it except in very simple situations.

> The Haskell community is full of people who are here to geek out rather than produce software.

The Haskell community is full of people who are here to geek out about the best ways to produce software. This means they embrace tools like mathematics, and are generally extra thoughtful about structuring programs in principled ways. It's a wonderful community of people who care about the details of their craft and treat it like a skill to be honed over time. I have a lot of respect for that.

If I could rant for a moment: I'm really sick of spending many years of my life investing in myself and my ability to produce software with the best tools humanity has to offer, only to have these people in Hacker News tell me I'm just doing mental masturbation when it seems like they don't even understand what they're criticizing.

ebingdom··on Functors and Monads for People Who Have Read Too Many “Tutorials”
> I still think they don't often come up in algorithms research, though.

Why are you so fixated on algorithms research in your attempts to dismiss the usefulness of functors and monads?

ebingdom··on Functors and Monads for People Who Have Read Too Many “Tutorials”
> monads have very specific properties that imperative code often doesn't have.

You don't know what you're talking about. In the context of programming language theory, monads were first used by Eugenio Moggi precisely for the purpose of specifying the semantics of imperative programming languages. Only later did Wadler realize that they could be useful as user-defined constructs within a programming language.

The "very specific properties" are actually just the identity and associativity laws of a certain monoid. These are trivially satisfied by imperative-style code including the "algorithms research and papers are expressed in imperative pseudo-code" you mentioned: you can write an imperative program that does nothing when sequenced with other programs (identity), and A; B; C does not require explicit grouping (associativity).

> It's only Haskell's laziness that makes it require monads for i/o, by the way. Other pure functional languages don't use them. For example, in Idris, IO and state are not monads, they are effects - tracked at the type system level, but without all of the commodity of monads. For example, you can have a single do-block in Idris that does IO and state operations without needing any monad transformers or lifting.

This is an incoherent train of thought. Haskell's laziness does not require the explicit use of monads, nor are monads only useful in the context of laziness. Haskell could have used Idris's IO system instead—algebraic effects work just fine in lazy languages. But also it is not true that Idris programs do not use monads just because you don't see the word "monad" in Idris programs. Effects give rise to a monad, mathematically; namely, the free monad for the algebraic theory. Read the seminal work by Plotkin and Pretnar, for example.

ebingdom··on Functors and Monads for People Who Have Read Too Many “Tutorials”
> much easier for humans to intuitively reason about than complex category theoretical concepts.

We're not talking about any complex category theoretical concepts here. Functors, for example, are one of the first ideas one would learn in a category theory course. Likely even in the first lecture.

Even the most advanced functional programs use only the most basic categorical constructs.

And when you say "imperative pseudo-code", you've already conjured an implicit monad involving state, I/O, etc. Functional programming just teaches us that it's not the only one—and there are simpler ones that may be more appropriate for the given situation.

ebingdom··on Functors and Monads for People Who Have Read Too Many “Tutorials”
> I strongly dislike Haskell's focus on theory.

First of all, I completely understand where you're coming from.

But the fact that Haskell embraces computer science, unlike most other programming language communities, is what attracts me to it the most. I can geek out about the mathematics that leads to simpler, safer software with like-minded people. I am always learning from Haskellers more than from any other programmers.

But it does take a lot of learning and unlearning to become a fluent functional programmer. This isn't because functional programming is more complicated than other paradigms (au contraire), it's because schools and universities have been mostly teaching OOP for the past 2-3 decades—unfortunately. As a result, most programmers have such a big gap in their knowledge that it can feel too daunting to dive in.

We could definitely do a better job teaching the theory and explaining how it's useful. That would be better for everyone: better for curious minds who want to expand their programming skills, and better for me because I'd have more company to discuss it with.

ebingdom··on Functors and Monads for People Who Have Read Too Many “Tutorials”
> Furthermore, even in Haskell, there is no such thing as the category of Haskell types[0] (because of things like divergence and partiality).

Divergence and partiality can easily be modeled by the category of complete partial orders and Scott-continuous maps. This is what you learn in, e.g., a course on domain theory and/or denotational semantics.

Andrej Bauer is mainly arguing that Hask isn't a category because no one has formally specified it. For example, we would need to come up with a policy on when two arrows are considered equal, and it's not clear what that notion of equality should be.

ebingdom··on Go Error Handling Proposals
Because the typical situation with error handling is that there are two possible cases: (a) a function succeeds with some result, or (b) it fails with an error. A sum type represents those two possibilities exactly. In contrast, a product type says "I have both a result and an error", which makes no sense. However, if things can be nil, which is the norm in Go, then you can represent both (a) and (b) with a product type, but you also have two additional cases to worry about: (c) both the result and the error are present, and (d) both are nil (and what are you supposed to do in that situation?).

When using static types, it is best to make as few nonsensical/illegal/invalid states representable as possible, so that you can rely on the compiler enforcing that they won't happen. Functional programmers have been saying this for decades, and these days Rust programmers are generally onboard with this too.

Sum types are the categorical dual of product types, so it always seems unnatural to me when a language only has the latter and not the former. I think part of the problem is we don't teach category theory to programmers, so they never stop to consider the duals of things.

ebingdom··on Go Error Handling Proposals
Using product types instead of sum types to represent "success or error" is definitely something wrong with it. Product types should be used for "and", and sums should be used for "or".
ebingdom··on The Repeated Deaths of OOP (2015)
> From the Swift docs regarding closures

What makes you think Swift only supports functional programming?

> I would have used Haskell doc reference

And if you would have, you would have disproved your own point. In Haskell, closures cannot mutate state, because mutable state is not part of the language semantics. It's modeled explicitly via monads.

ebingdom··on The Repeated Deaths of OOP (2015)
To all the people downvoting me: if you really think OOP is as well understood as FP, learn some programming language theory. Tell me what the universally agreed foundation of OOP is. You won't be able to, but I can tell for FP it's lambda calculus.
ebingdom··on The Repeated Deaths of OOP (2015)
Yes, that's one of the most prominent in a long line of attempts at creating formal models of OOP. And in the preface, you'll find:

> There is a well-established theory of functions, the λ-calculus, ... However, our theory of objects is self-contained; it is the first that does not require explicit reference to functions or procedures.

So that answers your question in the negative and proves my point: no, not every language is based on lambda calculus.

ebingdom··on The Repeated Deaths of OOP (2015)
> Isn't every existing programming language eventually based on (or at least traceable to) lambda calculus?

Not really. FP has an obvious connection to lambda calculus. Many OOP languages don't even have a straightforward notion of "function", which is what lambda calculus is all about.

ebingdom··on The Repeated Deaths of OOP (2015)
> FP is a cult.

It's a programming paradigm based on simple, well-understood mathematical framework. It's also the starting point for most research in programming language theory.

ebingdom··on The Repeated Deaths of OOP (2015)
It's true that functional programming also doesn't have a formal definition, but I wouldn't say it's "exactly the same" as with OOP. Functional programming is based on a simple well-understood mathematical model: lambda calculus. While there are different flavors of lambda calculus, they are related in obvious ways and one can reach formal conclusions them as a whole, e.g., the Church-Rosser theorem. In contrast, the many attempts to formalize the essence of OOP have resulted in countless wildly different results, so it's impossible to say anything meaningful about OOP, with the possible exception of this sentence.
ebingdom··on The Repeated Deaths of OOP (2015)
I would say it doesn't have a formal 100% unambiguous definition, but it's certainly _more_ well-defined than OOP: a functional programming language is one which is based on lambda calculus.
ebingdom··on Functional Programming in Go with Generics
> > it enhances the ability to reason about code

> In your opinion.

Correct. But my opinion is informed by years of experience with functional programming, procedural programming, and OOP (each).

> Please provide any evidence that this is true, especially the ‘safe’ part. Any study I’ve read says there’s almost no effect on language choice at all on bug rate.

Sure, here is a paper which provides the evidence you're looking for: "A Large Scale Study of Programming Languages and Code Quality in Github" (https://dl.acm.org/doi/10.1145/2635868.2635922). That paper concludes:

> The data indicates functional languages are better than procedural languages; it suggests that strong typing is better than weak typing; that static typing is better than dynamic; and that managed memory usage is better than unmanaged.

I personally don't trust academic studies on programming language effectiveness, since they often contradict each other (e.g., https://arxiv.org/abs/1901.10220 contradicts the paper I cited above). But if you're looking for a peer-reviewed paper, there you go.

Choosing the right paradigm absolutely has an effect on the bug rate. If you have to write more code, repeat code, or deal with low-level details irrelevant to the problem at hand, you are going to make more mistakes. On top of that, functional languages often have better type systems than procedural/OOP ones, which helps with bug catching that much more. Taking this to extreme, with dependent type systems you can actually verify arbitrary mathematical properties of your programs.

How much experience do you have with functional programming? I have professional and academic experience with both functional programming and OOP, and everyone I've met with that experience agrees about the trade-offs I've been discussing in my comments.

ebingdom··on Functional Programming in Go with Generics
I think this is a reasonable point, and of course you could take it further and say that assembly language is better than functional programming when you're doing work that requires you to reason about what the CPU is doing exactly.

But I would argue that the majority of Go programs should not require the programmer to follow the intimate details of a program's execution when trying to understand the business logic. The fact that the language has a garbage collector would suggest that it was designed for programs where some details can be hidden away.

So I agree with your general point, but I am somewhat skeptical about its application to Go.

ebingdom··on Functional Programming in Go with Generics
I would say the imperative version is easier to read in this article. The functional version doesn't really illustrate the benefits of functional programming very well, IMHO. I think there are two issues that reduce the effectiveness of the example:

1. Both examples contain a bunch of extra logic that has nothing to do with the difference between the two styles. For example, the code that converts users to that `UserLevelPoints` struct takes up a lot of space in both examples and is essentially the same in both. I think it would have been better (for pedagogical purposes) to just return the users (or perhaps a simpler struct containing a level and a user).

2. Both examples still have all the verbosity that is typical of imperative code, since it's still Go after all.

If one were to write the same function in a syntax which was designed for functional programming, the result might look something like this:

    topUser = head . sortBy points
    topUserPerLevel = topUser . values . groupBy level
I find this vastly quicker to read and understand than either of the examples in the article. But that relies on me knowing the functional-optimized syntax (e.g., that the `.` operator is just function composition), and for most imperative programmers that is the main hurdle. Since I am familiar with both styles, I can tell you that this would take me about 6 seconds to understand, whereas understanding each of the examples in the article took me at least a minute to even read the code, let alone understand it—and if there were bugs I wouldn't have noticed.

In contrast, with the simple functional version I provided, I can read it in seconds and be reasonably confident that it is correct (assuming all the pieces fit together in a valid way, which a type checker can check for me).

If the unfamiliar syntax prevents you from grokking the example I provided, it's reasonable to assume it's just some clever code golf that should be discouraged in production code. But please resist that temptation; this is actually what good code looks like. It's simple, not repetitive, and there aren't many places for bugs to hide.

ebingdom··on Functional Programming in Go with Generics
It's a shame that someone can become so misguided about functional programming. Functional programming isn't about destroying readability. It's actually the opposite; it enhances the ability to reason about code by (a) being disciplined about where side effects are allowed to happen, and (b) leveraging reusable abstractions for common patterns (e.g., transforming each element of a list, building a generic container that can be used for arbitrary types without sacrificing type safety, etc.) rather than re-inventing them every time with copying and pasting. Generally, functional programs are safer and shorter than their procedural/OOP alternatives, which is a good thing. Less code means fewer places for bugs to hide.
ebingdom··on GADTs for Dummies
Um that's just an ADT, not a GADT...
ebingdom··on Half a million lines of Go
Yes, I've worked on several Go systems. Nothing I mentioned about the language is an assumption; these are well-documented properties of Go. I've also have experience in a handful of languages which have more disciplined type systems (Rust, Haskell, Ocaml, TypeScript, , Kotlin, ...), and it's a night-and-day difference in terms of safety and reliability. Being able to confidently know that you've handled all error cases, that null pointers aren't hiding in your data, etc. is useful for safety.
ebingdom··on Half a million lines of Go
Why would anyone want to use a programming language that uses product types instead of sum types for the return types of functions which can return errors? Or why would anyone want to use a language that doesn't even let you write a type safe hash table? Also, the fact that Go suffers from the billion-dollar mistake is downright inexcusable. Go is way too error prone for me to sleep comfortably at night, because the lack of a reasonable type system is a constant liability.
ebingdom··on Things you can’t do in Rust (and what to do instead)
Yes, that is what they are, but a generalization of a thing is not the same as the specific thing, and in this case the generalization already had other names (since it has been around for many decades in many other languages). It would have been preferable to use one of the existing names instead of adding a new one and thereby complicating the story.
ebingdom··on Things you can’t do in Rust (and what to do instead)
> Rust's enums (used to illustrate static dispatch) are amazing, and one of the best (of many) language features. Enums can contain data of their own (as enum structs or enum tuples), opening up many more possibilities than the example might imply.

Algebraic data types are table stakes for any programming language in my book. I don't know why it's taken OOP programmers so long to come around to them (and most still haven't). It bothers me that Rust calls them "enums", even though "enum" already means something different to most programmers and we already have several terms that describe the feature that Rust has (coproducts, variants, sum types, discriminated unions, tagged unions, and, more generally, algebraic data types). This makes talking about programming languages more difficult than it needs to be, since when someone says "enums" I now have to ask what programming language they are referring to, since "enum" now means different things in different languages.

ebingdom··on The Plan for the Rust 2021 Edition
Yes, but they are opt in, right?
← PreviousPage 4 of 5Next →