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. 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.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.
(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.
I suggest the following plausible points:
1. Nobody is born knowing a programming language. Languages have users to the degree that they convert non-users into users.
2. Sometimes people are forced to use a language for a job (which is, I suspect, somewhat common, but less common than hiring someone who already knows the desired language). Others are forced to learn it to pass a course. Other than those cases, though, languages convert non-users into users in proportion to how much a non-user gets rewarded for the first attempts to write code in that language. This was one of the virtues of BASIC, for example. I picked up BASIC from the TRS-80 manual in an hour, and was writing code that afternoon. I got immediate feedback (we didn't call it a REPL on BASIC, but it had one). You could just read BASIC code.
But if I have to learn a mathematical notation, or a 1000-page book, in order to be able to do anything that I want to do, I have to want to learn that language more before I'm going to bother to learn that language.
Other than university people, Haskell seems to attract people who have been around the block enough times to know why they might want to learn FP, and therefore who care enough to make the effort.
The other version, however, is more readable to anyone who isn't a software developer by profession, but has been exposed to at least some code or even pseudo-code. It's the difference between turning people off of programming versus keeping them interested.
It's not a tautology. Especially in a language like Haskell, where it's very easy to write incomprehensible programs, even to experts, by following “common sense” principles.
> The other version, however, is more readable to anyone who isn't a software developer by profession, but has been exposed to at least some code or even pseudo-code. It's the difference between turning people off of programming versus keeping them interested.
I don't want to turn anyone off, but I also don't want to make an effort to accommodate people who aren't willing to learn. If other people like programming for what it is, that's great! If they don't, well, that's okay too. To each their own.
If you had never seen +,-,%,• before, simple math statements would be inscrutable. But, once you take the (short) time to learn them you can express things much better than if you had to write `add`, `subtract`, etc everywhere.
A point that is particularly poignant to anyone who has ever dealt with code using custom numeric types in a language that doesn't let you define custom operators (or overload operators).
Absolutely, anyone with programming experience can make sense of the longer (and still quite terse) version.
whileM ((<=) <$> readLeftIdx <*> readRightIdx) $ do
is literally symbolic soup without knowing the context and language in which it is written. For example `(<=)` could be less than or equal, but then again, given all of the other operators, who knows, might pipe output into whatever's calling `whileM`.Is that true? I'm skeptical.
Why is the "<-" symbol clearer to you? In particular, why did the commenter above write
li <- readLeftIdx
instead of let li = readLeftIdx
?I don't think anyone with programming experience could correctly answer this question unless they also have some specific Haskell experience.
What exactly does "return" do? I don't think someone without Haskell experience has any chance of answering that correctly, because it does not have the same meaning that it does in most languages. You might be able to make a reasonable guess, but you're unlikely to actually get it right.
I think once you're at the point that you can completely understand and answer these questions, the odds are high that you'll appreciate a more economical syntax for these operations.
As for return, even if the semantics of return are different in Haskell the keyword itself is quite common in programming languages. Therefore, given that it's the last statement one can assume that it returns the result of `(li <= ri)`.
If you know Haskell then the one liner is likely obvious. If not, not at all, there's a lot of domain specific knowledge required to grok what the one liner actually does. The long form version at least provides some guide posts to work off of.
No, that's not what it's doing. It's not imperative assignment. It's not even a `let` binding. Against popular belief, you actually need to learn a programming language to make sense of code written in it.
> If you know Haskell then the one liner is likely obvious. If not, not at all, there's a lot of domain specific knowledge required to grok what the one liner actually does.
s/Haskell/C/, s/one/hundred/g
The point is that everyone can take a guess as to what's happening in the long form version.
What about monadic actions that may return less or more than one value? For instance, parsers for languages with non-deterministic grammars, that return all valid parse trees, rather than just the zeroth one.
> The point is that everyone can take a guess as to what's happening in the long form version.
And that guess would often be wrong.
At the same time, I think it's less valuable than it might seem. A vague, cursory understanding is enough in this case to get a gist of what's happening, but it's not enough to actually work with the code, except via luck. The intuition you describe works okay in this case, but it would fail somewhat spectacularly in other cases, for instance with the non-determinism of the list monad.