5 ms·
>>As for your comments on lenses and records, I've been writing Haskell for a good number of years and still haven't really spent the time to grok lenses. I thi
by tmptmp 10y ago
>>As for your comments on lenses and records, I've been writing Haskell for a good number of years and still haven't really spent the time to grok lenses. I think they're probably great, but certainly mastery of them is not required to be productive with the language.
Give me any non-trivial industry scale web/database application which doesn't rely on the notion of records. The support for records in Haskell is if not pathetic is very poor.[1] (This is a rather older reddit post but I haven't kept track of it.)
I can be productive with Haskell if I restrict myself to math-type pure computations (e.g. DSL compiler) but if you want anything to do with web/database type non-trivial IO using Haskell, good luck.
So, I restrict myself to use Haskell only for doing pure computations that require extremely simple and trivial IO (mostly just readFile/writeFile).
>>This is an oft-repeated criticism of Haskell which I frankly find has no basis. Firstly, symbols are preferred for these kinds of functions precisely because of their ubiquity.
How about Haskell's notion of fixity of the symbols/operators/names?
It seems this almost arbitrary fixity [2] notion just adds cognitive overhead with little to zero semantic benefits. Correct me if I am wrong and please enlighten me on exactly what semantically significant benefits are offered by the notion of fixity and at what cost.
Most other mainstream languages don't offer such a useless flexibility like fixity which causes so much cognitive distraction when used by different people with different semantics, and that too just for kicks.
[1] https://www.reddit.com/r/haskell/comments/k4lc4/yesod_the_limitations_of_haskell/ https://www.reddit.com/r/haskell/comments/k4lc4/yesod_the_li...
[2] https://www.haskell.org/tutorial/functions.html https://www.haskell.org/tutorial/functions.html
- mightybyte 10y ago> How about Haskell's notion of fixity of the symbols/operators/names? Every language has implicit fixity and precedence for infix operators. What's different about Haskell is that you can actually define infix operators yourself. And if you're going to define your own you need to be able to also define the precedence of your operators. Fixity has always been there. You just didn't realize it.
- tmptmp 10y ago>>Every language has implicit fixity and precedence for infix operators. What's different about Haskell is that you can actually define infix operators yourself. It seems I didn't make my point clearer. I am asking what is the semantic benefit for the programmer of the explicit fixity and ability to change fixity at one's will? The whole notion of explicit fixity in Haskell exists because of Haskell's fetish (pardon me using this term again) for symbols instead of functions-names with fixed implicit fixity. They needed to support explicit fixity only because they wanted the programmers to be able to define operator symbols arbitrary with arbitrary fixities. So, now when you wish to read someone's code, then other than dealing with the inherent complexity present in their code, you also have to deal with the intentionally inflicted accidental complexity (to paraphrase Fred Brooks) over there because of their choice of using symbols with arbitrary fixities. [1] IMHO, Haskell adds to accidental complexity in this way instead of curtailing it just to satisfy their urge on usage of arbitrary symbols. Let me explain it a bit further: to read someone's code, first I have to see what symbols they have defined and what fixity they have ascribed to each of those. Now I have to keep all that additional unnecessary cognitive load in my brain to just be able to get a hang of their code with their fixity rules associated with their symbols. [1] https://en.wikipedia.org/wiki/No_Silver_Bullet https://en.wikipedia.org/wiki/No_Silver_Bullet edit: s/symbols over functions/symbols instead of functions/
- mightybyte 10y agoWhy does any programming language have infix operators? Because they make some things easier to read. Fixity and precedence are not accidental complexity. They are the essential complexity of having infix operators. In order to evaluate "3 * 4 ^ 3 ^ 2 / 4 / 2 + 5 * 8" you must define the fixity and precedence of the operators involved. You don't usually have to think about defining these things in most mainstream languages because the language defines the fixity and precedence of those operators for you to give the behavior you expect. You still have to learn it though. Do you know how Python evaluates the above expression? (Change the carets to double stars...HN didn't render double star properly.) In my first programming class long before Haskell was created, the textbook had a C operator precedence chart. The concept is not new to Haskell. Haskell has just given you control over something that has been there the whole time. Haskell lets you make your own infix operators so that you can get the same benefits in other domains than the ones that the language designers decided to provide for you. Therefore it follows that Haskell also needs to allow you to specify the fixity and precedence so that your operators will fit together in the way that is appropriate for your domain. > Let me explain it a bit further: to read someone's code, first I have to see what symbols they have defined and what fixity they have ascribed to each of those. Now I have to keep all that additional unnecessary cognitive load in my brain to just be able to get a hang of their code with their fixity rules associated with their symbols. The same is true of C, Java, Python, etc. The only difference is that those languages have a closed set of operators while Haskell's is open. There is a small amount of cognitive overhead, but I think you're greatly exaggerating it. In six and a half years of professional Haskell development I can count on one hand the number of times this has been an issue. And it can be trivially resolved by adding parentheses or by decomposing the expression into separate expressions.
- thinkpad20 10y agoFirst of all, I never claimed that libraries didn't use records; certainly nearly all do. I was talking about lenses when I said you don't need to master them to write good code. I'm not sure what it means for a record system to be "pathetic", but although there are issues with records in Haskell, it (a) is improving with new features forthcoming in GHC and libraries, and (b) has not stopped developers from writing millions of lines of robust, practical code. I think the "record problem" in Haskell is a legitimate one but not one which will ever prevent you from writing good code. At worst it's an annoyance. As to the questions about fixity, this is once again in practice not a big problem. First of all the notions of operator fixity and association are familiar to all of us since grade school. We all know "please excuse my dear aunt sally" or some similar mnemonic for the precedence rules of the operators of arithmetic. It's this rule that lets us write "a^2 + 2 * b^2 * c^(2 / 3)" instead of "(a^2) + ((2 * (b ^ 2)) * (c ^ (2 / 3)))". In other words it's a way to make an expression easier to read and parse by removing superfluous parentheses. It's not arbitrary at all, and in fact operator precedence rules is a feature that every other mainstream language has. As to what semantic benefits there are to fixity, fixity is a purely syntactic notion. It has nothing to do with semantics. Giving your operator an associativity and precedence only affects how a particular expression is parsed, not how it's interpreted or evaluated. I'd like to mention that your comments so far seem unnecessarily combative and hyperbolic. You use phrases and words like "pathetic", "good luck", "useless flexibility", "zero benefits", "please enlighten me". This injects contention into a discussion where there needn't be any. Furthermore, your statement that you only use Haskell for pure computations with minimal IO makes me question the legitimacy of your criticisms. Certainly, there are countless others who have written all manner of heavily interactive programs, web servers, database interaction, or IO-intensive programs in Haskell. If Haskell isn't your cup of tea, that's fine, but do you really think you're in a position to be leveling such criticisms when your own usage is so restricted?
- dllthomas 10y ago> The support for records in Haskell is if not pathetic is very poor. Be specific. Support for record field access is fine. Support for record creation is fine. Support for pattern matching on records is fine. There are two "problems with records" in Haskell. First, unlike many languages, records don't create implicit namespaces, so if you define Foo { x :: a } and Bar { x :: b } in the same module you have ambiguity. This is addressed, in part, by several recent GHC extensions. It could always be handled by putting Foo and Bar in different modules (with some added complexity if Foo and Bar are mutually recursive), but the community has settled on prefixing (Foo { fooX :: a }, Bar { barX :: a }) which is a little ugly but perfectly workable. Second, while support for member update is okay when shallow, it compounds in a particularly nasty way when it gets deep. So what in Java would be "x.y.z.a = 7", in Haskell is something like "x { y = (y x) { z = (z (y x)) { a = 7 } } }" - horrific, I agree. But note that "x.y.z.a = 7" isn't great practice in Java, either! Why do I know about the fields of a field of a field of my object? Far better if that's packaged up in a setter. And if you define setters, the Haskell gets cleaner too. Lens is a principled way of defining getters and setters (and more) that can be composed and manipulated consistently - but it does have a huge vocabulary which obviously creates a barrier until you've learned it. But you don't need lens to write setters (and for that matter, you don't need to know all of lens to use some pieces of it). I've also found that RecordWildCards makes records genuinely nice to work with in many cases - unpack the record into the local scope, at which point the prefixed names don't seem verbose, transform things as I want, and then re-collect the fields I can while explicitly setting those I need to.