10 ms·
Thoughts on Haskell
- michael_fine 11y agoThis 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.
- kushti 11y agoDear 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 11y agoCan't tell if you are being sarcastic.
- kushti 11y agoNo, 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.
- spion 11y agoI would disagree about Scala - I tried to get started with it and often got utterly confused. Haskell was easy by comparison - sure there were lots of concepts to learn but less gotchas and much cleaner syntax made up for it.
- LeonidasXIV 11y agoThe 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 11y agoYeah, 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.
- Mikeb85 11y agoDisagree entirely. 'Bigger' languages (think C++) are more difficult to learn. Haskell is a great functional language to start with - the language core is small, it's easy to use, and the 'purity' of the language means you don't start off cheating by using things like loops.
- maxander 11y agoThis 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 11y agoI'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.
- icebraining 11y agoIt's not either/or - you can make it optional, like in Python.
- danharaj 11y ago> 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.
- cruhl 11y agoA lot of people don't realize Haskell can be used without whitespace sensitivity C-style.
- david-given 11y agoSure, but as all code that actually exists in the real world uses the whitespace sensitive syntax, you're still going to have to interact with it to get things done.
- Retra 11y agoAlmost 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 11y agoA 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;
- mercurial 11y agoThat's a pedantic argument. What "whitespace sensitivity" means when talking about Python/Haskell vs other languages is fairly well-understood (use indentation to delimit blocks). For my money, I'll take Python's consistent use of ":" to start a block, though.
- evincarofautumn 11y agoAnd unlike in Python, in Haskell the whitespace-sensitive syntax is just sugar for curly braces and semicolons, which you are free to use instead. Even so, people overwhelmingly prefer the whitespace syntax, so the author’s dismissal isn’t backed up by the evidence.
- lolo_ 11y agoI 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 11y agoTo 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 11y agoIn my experience, Haskell is not the language you are looking for if you want to reason about runtime memory usage :(
- lobster_johnson 11y agoBlame the people here, not the language. The thing about quicksort is that it is explicitly in-place, something which goes against Haskell's programming model, so the code (if you use mutable vectors) ends up looking like C. It's not a lot worse than the C version, but it is unidiomatic Haskell, and so is considered bad form; much like an implementation of lazy evaluation or monads would look terrible in C. But you probably wouldn't pick quicksort to begin with. People should just stop using it as an example of Haskell's elegance.
- rjeli 11y agoRe: 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
- MaxGabriel 11y ago92 `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 11y agoI 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 11y agoYeah, grave accents are not exactly designed to be used as quote characters.
- MaxGabriel 11y agoThey're commonly used as such in several programming languages (https://en.wikipedia.org/wiki/Grave_accent#Use_in_programming https://en.wikipedia.org/wiki/Grave_accent#Use_in_programmin...), though, including Bash, D, Go, Ruby, MySQL, Markdown, etc.
- evincarofautumn 11y agoI don’t like them here or there. I don’t like them anywhere.
- chrisaycock 11y ago> I'm not familiar with other languages that have support for named, infix functions. Are there better syntactic alternatives? A "dyadic function" in q/kdb+'s .q namespace has a kind of Currying that accepts the right-hand value as the second argument to the function. (This is abusive in practice since the user should never add to the .q namespace as future conflicts are possible.) .q.add:{x+y} 5 add 10
- spion 11y agoWell, 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
- danpalmer 11y agoWhile 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.
- gh02t 11y agoHis point about partial application with multi-argument functions is something that has always bothered me. It's rarely a problem for me with two-argument functions since most functions have the order such that the first argument is the one you want to fix (and if not there's always flip), but with functions of higher arity it's not very elegant.
- kornish 11y agoAnother 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.
- oconnore 11y ago> 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 11y agoI wonder how those people ever get used to C++.
- juped 11y agoYou 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.
- mercurial 11y agoStuff 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).
- framp 11y agoHaskell 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/