
Thoughts on Haskell - mr_golyadkin
http://khanlou.com/2015/10/thoughts-on-haskell/
======
danpalmer
While the author is entitled to their opinion, I think there are other ways of
looking at most of the points made where they are advantages rather than
disadvantages.

For example, the author complains about the obscure operators. I'd agree, some
can be obscure, but the beautiful thing about Haskell is that they are not
language operators, but rather just functions, that anyone can define
themselves in the language! The fact that the power to do that is made
available to the programmer, in a safe way, is something very few other
languages manage.

The point about map, fmap and liftM (as I understand it, I might be wrong) is
not entirely correct, in that they apply certain constraints to their usage.
This helps to document the code, and also allows us to use precisely what we
need, and no more, which leads to safer programming.

As for whitespace - no one likes to read or maintain code with inconsistent
whitespace, which means whitespace is significant, regardless of whether the
compiler cares or not. So I find this complaint is worth less than many people
think.

Finally, the infix notation doesn't look particularly pretty, but you can also
define infix functions, so in practice I'm not sure this matters too much.

~~~
kornish
Another example of a touted inelegance which I consider to actually be
incredibly helpful in practice is the positional arguments part of the post
where the author says:

> For example, the Haskell function elem returns whether an element exists in
> a list. Do you call it with the list first or thing to search? There's no
> way to know.

Well, the type of `elem` is

    
    
      (Eq a, Foldable t) => a -> t a -> Bool
    

So, it is - with practice - clear to see that the singular item comes first,
and the item in the foldable container comes second. Perhaps this sort of
Type-Driven Development, which is more of a practical mindset than language
feature, isn't emphasized in the (excellent) books from which the author was
learning...but it becomes an invaluable tool in Haskellers' toolboxes while
trawling through package documentation later on. Many times, between the name
of the function and type of arguments, one can figure out exactly what they
need to pass in to achieve the desired output.

~~~
LeonidasXIV
> Many times, between the name of the function and type of arguments, one can
> figure out exactly what they need to pass in to achieve the desired output.

Yes of course because the parameters are usually designed with currying in
mind, so the order is from most general on the left to the most specific on
the right. In the case of elem, both orders are reasonable, but often times
only one makes sense and then it is easy to remember.

~~~
kornish
I'm not quite sure how you're defining "general" and "specific", but I think I
don't disagree with what you're saying.

The point of my comment was more that one of the beauties of Haskell is that
positional arguments are made so elegant because every positional argument is
accompanied by a type. I wasn't making a statement about the order of
parameters themselves, but how all parameters are typed.

> In the case of elem, both orders are reasonable, but often times only one
> makes sense and then it is easy to remember.

In some languages where callbacks taking positional arguments are idiomatic
(like Javascript), untyped functions can cause a lot of problems by making it
really hard to discern/remember what gets passed in where. In Haskell, there's
often very little onus on the developer to _remember_ anything at all; the
type system will make sure they got the order right.

Obvious exceptions are non-associative functions of the type

    
    
      a -> a -> a
    

Then, one might have to check to see what goes in first and what goes in
second.

~~~
tome
> Obvious exceptions are non-associative functions ...

You mean "non-commutative"

~~~
kornish
Absolutely right - good catch.

------
MaxGabriel

        92 `div` 10
    

> I think this is pretty ugly, and it feels like it was glommed on to the
> language in some kind of compromise. For div specifically, you can use the
> operator / to achieve the same thing, but this won't work for all other
> functions.

I don't see what's wrong with backticks for infix functions; they highlight a
change in fixity that makes it easier to see that `div` is being applied to
the surrounding arguments rather than being used an an argument:

    
    
        a div b
    
        a `div` b
    

I'm not familiar with other languages that have support for named, infix
functions. Are there better syntactic alternatives?

~~~
spion
I think its the backquotes. For a time I thought that

    
    
      a :div: b
    

would look better, but now that I'm used to the backquotes, I'm not so sure.

~~~
evincarofautumn
Yeah, grave accents are not exactly designed to be used as quote characters.

~~~
MaxGabriel
They're commonly used as such in several programming languages
([https://en.wikipedia.org/wiki/Grave_accent#Use_in_programmin...](https://en.wikipedia.org/wiki/Grave_accent#Use_in_programming)),
though, including Bash, D, Go, Ruby, MySQL, Markdown, etc.

~~~
evincarofautumn
I don’t like them here or there. I don’t like them anywhere.

------
oconnore
> I'm going to talk about some stuff which struck me while learning Haskell.
> This post is meant for people who write code in languages that are not
> Haskell, but would like to learn more about the experience of learning it.
> Like many of my posts, it's for past versions of myself.

It's baffling to me that people find the first two weeks of language
experience so interesting. Every language, even incredibly productive ones,
have idiosyncrasies that get you in the beginning.

Lets instead talk about how A compares to B after 6-9 months with similar
sized teams. Lets talk about on-boarding new hires once the organization has
built a skilled team in that environment.

~~~
marcosdumay
I wonder how those people ever get used to C++.

------
lolo_
I get a little annoyed when people talk about how _actual_ implementations of
algorithms are just a pedantic detail - no. A language that can do neat tricks
for a not-actually implementation of an algorithm which a lot of people then
blindly take as a great example of its 'elegance', while requiring a lot of
ugliness for a _real_ working implementation, is demonstrating something
important I think.

It reminds me a bit of marketing claims vs. reality for a product.

~~~
Almaviva
To me it feels like a microcosm of the difference between academic vs
pragmatic thinking. The reason to use a quicksort is not because it's elegant
and consise, it's because it is fast and memory efficient. When your
implementation of an algorithm is actually an algorithm with asymptotically
worse memory characteristics, it's not suitable for any real world production
code, and this difference is _not_ pedantic.

This is what gets me: Haskell articles tend not to stop at presenting this is
as a neat and elegant definition of a sort (which it is!) but emphasize that
you're a just being picky if you're not willing to brush aside memory usage
and reasoning about such in production code.

~~~
mercurial
In my experience, Haskell is not the language you are looking for if you want
to reason about runtime memory usage :(

------
maxander
This is the first time I've seen anyone complain about positional arguments.
While I can see the point of such a complaint (and its arguably even worse in
Haskell, where there's application-order confusion at the same time), my
impression is that the larger body of programmers are still miffed whenever
they have to explicitly name a type- explicitly handing every argument of
every function to a specific named field sounds _deeply onerous_ by
comparison!

I suspect the next Holy Wars in programmer practice will revolve around "how
much can we get away with not writing out?"

~~~
protomyth
I've made that complaint quite a lot and heard it quite a lot. I hung out with
a lot of Smalltalkers and I have programmed Objective-C since NeXTSTEP 3.3. I
like selector syntax and find it a pain in the butt when I'm in Perl or C
looking for the order of arguments. I guess its all in who you associated with
early. That's probably why I don't like Swift (which does it clunky) as much
as Objective-C.

------
michael_fine
This is a nice post that mirrors a lot of the thoughts I had when learning
Haskell. I especially agree about his point on position dependant partial
functions -- I think the idea of a placeholder symbol (maybe _) that you can
put in place of an argument to make it partial would make it a lot cleaner.

One quibble though -- he complains about the ugliness of infix functions, but
misses that you can define your own infix operators, with their own precedence
rules! Just put parentheses around the symbol(s) when defining the function,
and it becomes infix by default.

------
juped
You should really press the fmap thing - the most common reason given for it
not just being map is that "newbies might get confused". A coalition of
newbies confused by the unnecessary distinction would do wonders here.

------
danharaj
> I thought we were all in agreement that Python would be the only programming
> language that maintains structure through whitespace so that we could all
> ceaselessly make fun of it.

Haskell and its whitespace sensitivity are older than Python.

~~~
Retra
Almost every language has whitespace sensitivity, it's just a matter of
degrees.

For instance, in C the following lines have different semantics:

    
    
        int a = 3;
    
        inta=3;

~~~
rprospero
A more extreme form of whitespace sensitivity in C are the two following
statements, which are identical and differ only in their whitespace.

x = y++ + z; x = y + ++z;

------
spion
Well, record constructors try to fix the unnamed argument problem for product
types, and they turned out horribly wrong (the created functions are unsafe if
the record is part of a union).

It would be awesome if Haskell had _standard_ row-polymorphic extensible
records though, like PureScript or Elm

------
mercurial
Stuff I would have mentioned:

\- some_code... where vs let... in some_code: these two constructs play a
fairly similar role in Haskell. The problem with where is that it lets you
introduce the value of a binding AFTER using said binding. Ugh.

\- functions defined over several lines using pattern matching: I'm still not
sure if it's a good idea or not, but I think overall a shorthand syntax like
OCaml's "function" keyword (except less unfortunate) is better

\- pattern matching and guards are separated (try going back to Haskell after
trying a language which combines the two..)

-the absence of named and default arguments is an issue in a language like Haskell. This leads to many instances of "guess what the fourth argument here means"/"let's create a record type just for the arguments of this function" and elegant APIs such as function1, function1' and function2'' (good luck figuring out from the name only which function you need)

\- a much stronger focus on brevity (single-name variables all over the place,
horrible ASCII DSL galore) than on legibility

\- I think the record situation situation improved since I stopped doing
Haskell, but when I did, it was really a trainwreck (having to prefix the
field names of all your records to prevent collisions is not a feature).

------
rjeli
Re: confusing positional arguments- Functions are defined with partial
application in mind. So, is it more likely you are mapping values over a list
or lists over a value?

This is usually more readable as well. Consider:

    
    
      λ: 3 `elem` [1,2,3]
    

"Is 3 an element of 1,2,3?"

Also, div is not the same as (/):

    
    
      λ: 3 / 2
      1.5
      λ: 3 `div` 2
      1

------
framp
Haskell is not a perfect language - but I don't really agree on the points
raised by the author.

The things I don't like are:

\- String vs ByteString vs Text - seriously tired of csing everythin

\- Lazy by default is fun - but makes everything harder to optimize. What
would happen if Haskell were strict? [https://nikita-volkov.github.io/if-
haskell-were-strict/](https://nikita-volkov.github.io/if-haskell-were-strict/)

\- Records are not namespaced - [https://nikita-
volkov.github.io/record/](https://nikita-volkov.github.io/record/)

------
kushti
Dear Soroush, I think it's just way too early for you to play with Haskell.
Spend months or years with Scala/Ocaml and only then Haskell(please note, that
doesn't mean Haskell is better or whatever comparable to those languages).

~~~
dominotw
Can't tell if you are being sarcastic.

~~~
kushti
No, I just think after Objective C it's hard to get into a lot of new concepts
simultaneously. So it's better to start with those dirty hybrids where you can
start with imperative style to get into idiomatic OCaml/Scala approach then
and only after dive into pure lazy functional programming with strict static
typing. It would be useful to read "Types and Programming languages"(and maybe
some other books) as well on this road.

~~~
LeonidasXIV
The way to write imperative style in OCaml is so painful that I'd expect
people to just drop off on the way. I mean, it's nice that it's possible, but
I don't think it's a reasonable migration path.

~~~
mercurial
Yeah, don't get confused by the fact that there is an "O" in OCaml. This _does
not_ mean that you can write "imperative OCaml" the way you can use Scala as
"shorter Java". "Imperative OCaml" is much closer to "imperative Haskell"
without the monadic effect system.

