Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Haven't seen it listed neither here nor there, so not sure if I'm the only one, but: for me, the first and currently blocking obstacle is of "graphical" syntax. I'm of the kind of people who hear the words they read as a voice in their head, so when every line is interspersed with multiple "random" <:> >>= <=< @>-,-'-- and whatnot other ascii-art I can't verbalise, I distictly feel my brain stumble, mumble, and grind to a halt and sad emptiness. And I don't even know how to google any one of them. Don't know how to solve this for myself. I've once found a list of suggested names for some common ones, but - I don't like having to learn all that by heart before I even start with the language; and also I feel pretty certain those are not all, and many libraries seem to like to invent their own new ones, so back to square one.

That's I believe the main reason I find SML more attractive: it seems to use operators to a much, much lesser extent, apparently preferring alphanumeric function names in the core, and in 3rdparty libraries too.



I felt the same way (and still do in general, with notable exceptions). I.e. to put this first: I think a lot of the Haskell community is obsessed with mathematical "cuteness", which basically they take to mean "infix-operator-heavy" notation.

Nevertheless, I have learned to like some operators,

    <$> <*>, *>, <* 
are ones that come to my mind. The operator

    <$>
is basically fmap as infix notation, so `fmap f [1,2,3]` would be `f <$> [1,2,3]`. This makes mapping as easy as a normal function call (and the operator name `<$>` was not choosen arbitrarily. `$` by itsself is the function application operator, so `f $ 3` does on a single element, what `f <$> x` maps over an instance of Functor.

With applicatives, the pattern of

    f <$> a <*> b <*> c
is very common (with a type signature

    f :: a -> b -> c -> ....


Now that is the first time I see an explanation which tries to point out some sense in the apparent madness. Appreciated! Would you or someone else knowledgeable be willing to create a guide like this, but spanning all the magic runic incantations known to Haskell wizards? Showing similarities, analogies, etc? And targeted at dumb apprentices like me? I'd be happy to serve as a somewhat (though not perfectly) dumb specimen to bounce explanation attempts off! (email in my profile - just added, in case someone was crazy enough to try to pull that off)


It's nice that someone was trying to make things sensible. But what are the precedences of those operators? Maybe you would argue that you can expect them to be whatever makes the most sense. But what about the one case when they aren't what you expect and you're getting some confusing error (or, gasp, incorrect runtime behavior). Maybe a library designer made a bad decision about which precedence to give to a certain operator. Or maybe the choice was simply not so obvious.

I guess the solution is just to put parentheses everywhere, but why is it that, whenever I show people code where I'm doing that, they always point out "Oh, you don't need parentheses there." I feel like that just goes to show that the community underestimates the confusion most people feel when they encounter a jumble of custom operators and have to recall to themselves which parts of an expression are evaluated first or even in what direction. This language feature feels more like an antipattern.

I really think the benefits of making operators so easy to define are quickly outweighed by the drawbacks for most programmers. The infix culture seems like one of the biggest barriers for this language.


I concur with your uneasines about operators, I often find them used "too often" in Haskell, I have been a Clojure/Scheme guy in the past.

But: For Functors and Applicatives for example, they do make sense. If you are using them, you can use them in any program you write. Just like we found addition and multiplication with numbers build an abelian group and chose to represent these operations by "+" and "-" (with the difference that in Haskell Programs, Functor-capable data structures pop up everywhere).

So that being sad about the motivational level, I would like to address some of your arguments against operators on the syntax level.

Precendence can be a problem and obviously it is something that is and has to be learned and might confuse beginners.

Nevertheless, Haskell's typechecker will often tell you when you missed up. I started of parenthesizing the hell out of these expressions and let hlint tell me when I could remove the parens, after a few days I hardly made any of these mistakes anymore.

While - as a Lisp guy - i do prefer functions over operators quite a bit, it is not like it is a terribly difficult thing. People have committed to learn inheritance, and multiple inheritance. Write classes where the hold and manage a lot of state and let that state interact, etc. That stuff is magnitudes more complicated than Haskell operators, already on a conceptional level.


I think that your second indented block, which is currently

    <*>
, is supposed to be `<$>` (based on the rest of your discussion).


Yes, <$> is the general `map` (`fmap`)

  <*> 
takes function(s) out of a mappable and applies it (them) to argument(s) within a mappable.

  (+) <$> [1,2,3] = [add 1, add 2, add 3]

  (+) <$> [1,2,3] <*> [10, 20] = [(1 +), (2 +), (3 +)] <*> [10, 20] = [11, 21, 12, 22, 13, 23]

  (+) <$> Just 3 <*> Just 5 = Just (3 + ) <*> Just 5 = Just 8

  (+) <$> readLn <*> readLn = ... 
well that depends on the inputs :)


indeed, fixed it, thx.


It helps to read $ as "value". Then "function $ x" is "function value (of/at) x". Works in some other languages too, e.g. $VARNAME = value (of) VARNAME.


Haskell is too sugary; there's too many ways to write out exactly the same thing (semantically identical, not computationally). And most resources choose one way to do things over another and it all becomes fractured and difficult.

In comparison, J is all about symbols, but provide a canonical dictionary and strict semantics about how those symbols work. Still complex to learn, but easier overall.


The "separatorless" style is also another aspect of the syntax that's turned me off Haskell --- most other languages have characters like ';' that serve to delimit statements, ',' to separate list elements, and ample use of parentheses to clarify how things should be parsed (e.g. identifier followed by '(' signals "function call", and the matching one signals the end of the argument list.) In comparison, Haskell code reads to me like a giant run-on sentence where you need to make much greater use of context in parsing.

I suppose the other extreme is Lisp, which I've played around with and found quite pleasant because of its very unambiguous syntax.


In recent years, I've switched to a Haskell style that is much more "separator-ful". I chain my computations together using the `&`, `<&>` and `>>=` operators. These operators are flipped function application, flipped fmap, and bind.

They are all declared as left-associative with precedence 1, which means that they read left-to-right. i.e: they're the separators, so you don't need extra parenthesis.

So you can have something like:

  employees database
  <&> salary
  & sum
  & writeReport title
  >>= sendReport destination
This lets you read your data processing pipe-line, while also seeing what kind of effects are being composed together at each step.


I agree that Haskell library writers can assume too much knowledge of operator precedence on the part of their readers. It can often make it very hard to read unfamiliar code.


Haskell does seperate list items (and tuple elements, and record member assignments) with commas.

You are, of course, free to object to the lack of separators between (and parentheses around) function arguments. I find it pretty natural when everything is curried.


It can be overwhelming, and trying to use Google is terrible. There's a really nice Haskell specific search engine though: https://www.haskell.org/hoogle/ - you can query module/function names, type signatures, etc.

A lot of these weird "operators" are also typically defined with a synonymous named function. These types of operators are usually functions after all, not actual language operators.


Check out Hayoo (http://hayoo.fh-wedel.de/) -- I like it more than Hoogle


Also, fpcomplete's instance of Hoogle:

https://www.fpcomplete.com/hoogle

It searches on all the stackage set of packages, afaik (another explanation: http://stackoverflow.com/a/21955591/293735 )


As a counterpoint, I love this about Haskell.

It seems like my ability to hold logic in my head is partly visuo-spatial, and the terseness makes it easier for me to tell what's going on. (I also do Scientific Computing, so a general resemblance to mathematical notation is hugely helpful for me reading code).


I think similarly (I sometimes write code like this

  let A be sth
      X be sth else, ...
and then the equations and predicates and pseudocode using one-letter names). Then I change these to regular variable names of course (my friends don't think it's readable).

I also really like the fact that in clojure identifiers can use math symbols exactly for this reason. I love the fact that + is a regular function, that I don't have to wrap it to reduce or map with it, and don't have to remember how to turn it from infix to prefix or vice-versa. That it works with any number of arguments. Same with <, >, =.

This the prettiest definition of dot product I've seen in any programming language

    (reduce + (map * v1 v2))
It's great because with 2 very universal language constructs you get to express tons of stuff cleanly. There's no incidental complexity there.

But I just can't force myself to like Haskell operator-happy style. I've tried learning Haskell a few times, and never sticked to it for more than a week, because operators everywhere just make my uneasy, and there's too much specialized version of functions.

I tried to learn common lisp a few times before clojure and nvere managed to get through the weird historical naming nonsense. Haskell sometimes feels like common lisp in that respect.


> And I don't even know how to google any one of them. Don't know how to solve this for myself.

https://www.haskell.org/hoogle/ lets you search for functions by name, including symbol-named functions like <$> and co.

(You can also search for functions by type, which is a pretty cool feature, but not what you were asking for.)


Hoogle could help with the searching problem: https://www.haskell.org/hoogle/


Nice to know. Still, no spelling there, as far I can see. And no docs or examples either, apparently: https://www.haskell.org/hoogle/?hoogle=%3E%3E%3D is still a problem for me


One additional click on any of the links (usually the function name) brings you to the actual documentation.

https://hackage.haskell.org/package/base-4.8.2.0/docs/Prelud...

Edit: Granted ">>=" (bind is the word you are after) is kind of special and you need to understand more of the underlying language mechanics to get it. The provided explanation tells you little unless you can grok the function signature. I think it's almost universally accepted that a lot of the documentation is atrocious.


If you are ever confronted with a non-trivial parsing problem, have a look at Haskell again and use Attoparsec. <$>, <>, >, <*, <|> will become incredible concise tools for expressing your ideas!


> I don't like having to learn all that by heart before I even start with the language

I'm very curious about this. Why do you think you have to learn it all by heart before you start with the language?


I'd guess this happens when you don't know an easy way to look up the definitions on the fly.


Also I meant it about having to memorize the spelling.


I suspect this is due to its mathematician-heavy user base, who are very used to just defining new operators with a squiggle on the blackboard. The worst language for this was APL, where most of the common operators could not be typed on a normal keyboard.


If you find yourself needing to read Haskell, feel free to ask others how they pronounce things.


Interesting that Haskell goes in so hard for operator overloading. In other languages I've used, while you can overload a bunch of operators, it's not a common thing to encounter, outside of math code, where it makes the most sense. Technically you could do all sorts of crazy operators in C++, but that tends to be frowned upon in that community.


It's not operator overloading. It's using symbols as function names. Some operators like (<>) may have different implementations based on the Monoid instance of the underlying types, but they are based on laws which is different from say Python where >> can mean anything based on the context (even though it is used sparingly there).


I'm of the kind of people who hear the words they read as a voice in their head, so when every line is interspersed with multiple "random" <:> >>= <=< @>-,-'-- and whatnot other ascii-art I can't verbalise, I distictly feel my brain stumble, mumble, and grind to a halt and sad emptiness.

Incidentally, this is why prefix notation seems so foreign. (+ 1 2) reads as "plus one two."

It's possible to overcome this, with dedication. (And it's worth doing.)


Incidentally, this is why prefix notation seems so foreign. (+ 1 2) reads as "plus one two."

It might just be the Lisp version of Stockholm Syndrome, but it seems perfectly natural to me to gloss that as "Add one and two."


Good point. (eq (+ 1 2) 3) would read "is add one to two equal to three?" though.


One thing that long ago helped me to apprehend and appreciate the power of functional programming was to start thinking descriptively (in terms of facts and propositions) rather than prescriptively (in terms of imperatives and commands).

Thus, I read “(+ 1 2)“ as “the sum of 1 and 2” rather than ”add 1 and 2“. Similarly, I read ”(eq (+ 1 2) 3)“ as ”the difference between 3 and the sum of 1 and 2 is zero“.


"Are the sum of one and two equal to three" is how you'd read that.


Equal would come first for lisp.

"Would you consider equal the sum of 1 and 2 to 3?"


Lisp is read from the middle. (+ 1 2) sort of comes first since it's evaluated first.

Though now that I type that out, I'm acutely aware of how strange it sounds. Interesting.

It's also not true in the case of macros, e.g. let. So, you're right. No wonder it seems so foreign.


Don't use EQ to compare numbers. Use EQL or = .

EQ is object sameness. Number objects of the same value are not necessarily the same object.


"Equality of (sum of 1 and 2) and 3".

It's nice because it shows it's a value not a question.

But I don't really verbalize code, I think in symbols, maybe that's why prefix doesn't bother me.


Precedence is easier to parse with prefix/sexp/stack notation than infix.


Also, read as: "add one and two"




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: