5 ms·
I also find it strongly problematic that functional languages with customizable infix operators (e.g. Haskell and OCaml) have lines of code like this: whileM
by wcrichton 10y ago
I also find it strongly problematic that functional languages with customizable infix operators (e.g. Haskell and OCaml) have lines of code like this:
whileM ((<=) <$> readLeftIdx <*> readRightIdx) $ do
And, from what I've seen in a few Haskell codebases, this isn't all that uncommon. I refuse to believe that there's not a better way to express these kinds of programming patterns. I recognize that applicatives, functors, etc. have their value in creating well-engineered interfaces, but when they manifest themselves in obscure operators, it feels self-defeating.
- nilkn 10y agoWhile Haskell does have customizable infix operators which can be overused and abused, that line isn't a good example of the problem in my opinion. The three infix operators there ($, <$>, and <*>) are all extremely common in Haskell code and are built-in to the language. Every competent Haskell programmer will be intimately familiar with those three operators. The problem arises when new libraries introduce new infix operators. I find this highly annoying and almost always consider it a code-smell. So honestly we're in agreement in general, just not with that particular example. I consider those to be basically the "arithmetic operations" of function application. Considering the entire language is based on function composition and application, I don't think it's a bad thing for an economical notation to be used.
- bweitzman 10y agoWhile they may be common, they're not actually built into the language. They're just regular functions.
- deleted 10y ago[deleted]
- chadaustin 10y agoSure, they're library functions, but they're also specified in the haskell 2010 spec. That makes them built-in from a practical perspective.
- grdvnl 10y agoThe example you quoted is probably the very basic of operators and idioms being used. These operators have standard meaning in terms of fmap and applicatives. But, I agree with you that there are obscure operators scattered around the code base and I have to keep jumping away from that point to lookup what the particular operator means in that context.
- gohrt 10y agoWhat makes an operator "obscure"? Can functions be obscure too? What makes a function "obscure"? You don't like punctuation in your identifiers. It's a a fair objection, and a common one for people whose native language uses a small alphabet (as opposed to CJK and other languages that are ccustomed to using wide range of glyphs)
- catnaroek 10y agoDo you really think it would be clearer to write cond = do li <- readLeftIdx ri <- readRightIdx return (li <= ri) -- ... whileM cond $ do ... Personally, I don't think it adds much clarity. It just makes the code more verbose.
- timmytokyo 10y agoAs someone who doesn't know Haskell, I can understand your version. I had no idea what the other one does. Maybe that's not a reason to avoid the more concise syntax, but a language that is more comprehensible and intuitive to people unfamiliar with it is more likely to capture mind-share.
- catnaroek 10y agoBoth versions are equivalent. The reason why you didn't understand the original version is that, as you say, you don't know Haskell. But, if you learnt Haskell, the original version would've been just as easily comprehensible.
- timmytokyo 10y agoI get that and agree with you. My point is that it's easier to evangelize for a language that is intuitive and comprehensible with only limited exposure to the language. Languages like go are a good example of this. If you've ever done any programming, you can read go code and know what it does. even if you've never written a single line of go code in your life. I'd say Elixir, a functional programming language, is also good in this regard.
- catnaroek 10y agoMaybe I'm weird, but I make sense of code as much as possible from static information, without actually running it in my head: (0) Type signatures (obviously). (1) Abstraction boundaries - which implementation details are not exposed outside of a module, class, whatever. (2) Documented preconditions, postconditions, invariants and algebraic laws. (3) In impure languages, the scope of mutable variables and effectful procedures. > My point is that it's easier to evangelize for a language that is intuitive and comprehensible with only limited exposure to the language. I have to admit I don't care much for technological evangelism. I prefer to let technical merits speak for themselves. To be more precise, I'm okay with others showing me technologies I might like (“good” advertisement), but I'm not okay with others trying to convince me to like whatever they like (“bad” advertisement). > If you've ever done any programming, you can read go code and know what it does. That hasn't been my experience, and I've honestly tried. If you show me a heavily concurrent Go program, I can't easily tell on a first read whether the program is correct, or, if it's incorrect, where the problem might be. Just because I can run a program (in the sense of myself acting as the interpreter), it doesn't mean that I actually understand its design. :-p > I'd say Elixir, a functional programming language, is also good in this regard. I haven't actually tried it, but the fact it's designed to be similar to Ruby doesn't inspire much confidence on me. I don't mind Ruby's syntax, but the impossibility to make sense of Ruby code other than by trial and error is incredibly frustrating.
- LeanderK 10y agothe operators $, <$>, <> in haskell are like the pointer related stuff in c. Everybody knows what the difference between foo and foo is and what the arrow operator (->) does. Its just really, really common so you pick it up pretty quickly. I know its a bit overwhelming at first, but thats not because it is difficult, but because the paradigm is really different and it needs these quick but obscure operators to not drive developers insane.