-
-
Notifications
You must be signed in to change notification settings - Fork 189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
What was it like to learn Haskell? #854
Comments
Having fallen in love with functional programming after learning Scala, I wanted to learn more about functional programming. On several occasions, people mentioned that I should be doing Haskell, which was (according to them) the best functional language there was. Learning Haskell was tough though. At times I felt completely overwhelmed. The difference between Scala, which is a hybrid language, and Haskell, a pure functional language, was much bigger than I expected. I'm still not very fluent in Haskell, but in the end most of the concepts "clicked" and I started to really appreciate the things Haskell had to offer.
When learning Haskell, I primarily used the Learn You a Haskell for Great Good! website. It is well-written (even funny at times) and gives a good introduction in all the various aspects of the language. The best resource though, was Exercism! At the time, it was still v1 of Exercism, so there was no mentoring built-in. That said, each of my submissions had useful comments from Haskell users. It was invaluable to have this personal feedback, especially as I was struggling so mightily. Note: it was due to these Haskell mentors that I became convinced of the superb value of Exercism.
The usual mixture of trial and error, StackOverflow and blog posts. That said, Haskell is not a hugely popular language, so the amount of resources available was definitely a step back from what I was used to when doing C# or Scala.
There were lots of things new to me. Haskell is a pure functional language, which means that it has no side-effects (at least not in the classical way). Also, it has a very advanced type system, with concepts like type classes and advanced type inference. Haskell was also the first whitespace-sensitive language I used. The emphasis on function composition and a pointfree style of defining them was also new to me. The documentation to me was a step back from e.g. the C# documentation. Haskell documentation looks like (and probably is) automatically generated, technical documentation, and as such does not offer some of the rich documentation (including examples) I've gotten used to with C#. Haskell was also the first language I used without a proper IDE. As such, Haskell was also the first language I knew that did not primarily rely on a debugger to find issues. There was a much greater emphasis on using the Haskell REPL (which I now love). Haskell users also seemed to me quite academic, which meant that they were mostly very clever and regularly came up with solutions I didn't understand. They were also more at ease with more complex mathematics (like category theory) than I was. Haskell was also the first language that regularly mentioned the dreaded monad word :)
Type classes and getting used to a pointfree style was hard. Also the way side-effects are dealt with (in the type system itself) was really hard to grasp. I had also some issues with the fairly mathematical background of some Haskell concepts (e.g. category theory).
All of the functional programming staples I learnt when learning Scala: tuples, lists, pattern matching, sum types, type inference, function composition, etc.
Pointfree style made code very concise, but also required a bit more familiarity with function composition than I initially had. Type classes were very new to me, so I had some problems learning that. I also struggled with the documentation, at times cursing its conciseness and technical nature.
Using curly braces to define scoping. How to deal with side-effects.
One thing I did have to unmap was how to write lambda expressions (inline functions). |
My first experience with Haskell was playing around with some things with my roommate. We managed to get a few things to work, but it seemed fairly difficult to do things that I could easily do in languages I already knew. I continued learning the following summer and got more into it with the mentors here at exercism.io. It helped a lot to simply do things the way I could get it to work and then get feedback for improvements, more "idiomatic" Haskell, and shortcuts.
The online book "Learn You A Haskell For Great Good", "Real World Haskell", and the mentors here at exercism.io :-)
I would use the REPL and play around with types. Emacs has a good Haskell REPL, although it took a while to set up and get it working. I would search online for similar issues. I also used Hoogle extensively. After I started getting the hang of it, I would often think of a function I thought should exist, search by the type signature, and find it. This was often faster than searching in English what I wanted since people would often describe their problems in different ways. This also helped me discover that sometimes my problems were more general than I initially believed (e.g. It could apply not just to lists but to all
Haskell was different in almost every way! I had previously learned C++, Java, Python, and a bit of Emacs lisp. The biggest difference was the inability to have sequences of statements...since there were no mutable variables. At first, it seemed like it would be impossible to do anything without statements and mutable variables. It took a while for
It took a while to grasp type classes, as they were more abstract than anything I had done before. I remember lying in bed trying to wrap my head around Monoids and Functors and Applicatives and Monads.
List comprehensions in Python were probably the closest thing I'd done to functional programming.
At first, just being able to do anything. The Currying and closures were some things that took a little while but were a little easier than others. Also, type classes.
Mutability and shared state.
The syntax was so different that I didn't end up remapping too much. The operators were, for the most part, the same, so that wasn't too bad. |
I learned Haskell after OCaml. Both the syntax and concepts transferred over very easily (just to name a few: all functions take one argument only, I think the breakthrough moment when learning OCaml was "Aha! The accumulator in a fold doesn't necessarily just hold the eventual result! I can also use it to carry over information from one element to another!" (you could say, almost like state!). That opened the floodgates to understanding. That helped in all subsequent functional languages. Non-strict evaluation of Haskell sometimes makes it hard for me to predict how performant a given piece of code will be. I've caused my computer to run out of memory before for this reason. |
I learned Haskell in university after two years of being a teaching assistant in introductory functional programming using Standard ML. The course I took that covered Haskell, Erlang and Prolog was fast-paced, so I took a head start during the summer. This was very enjoyable because of the low pressure. Importantly: I am still learning Haskell, 9 years after installing GHC for the first time.
It was helpful to know a "simpler" functional programming language with strict evaluation. It was helpful to live in a university environment at the time. I struggled with type classes, and in particular monads, applicatives, functors, reader-writer-state monads and monad transformers. I recall there being a leap in understanding from trivial containers being monads to types that involve
I hit on things until they worked, redid the same exercises again and again, copy-pasted from the Internet, and eventually an understanding of what I had written grew on me. The biggest leaps in my personal understanding came from preparing teaching sessions, and from implementing an advanced programming pattern from the bottom up to experience when the need for an abstraction actually arises.
In most ways that matter; it is more abstract.
My assumption of strict evaluation.
I find that difficult to answer. I still experience syntax remap problems when I have not touched a language in a while -- e.g. Haskell uses
All the basics of functional programming. You can write Haskell without many abstractions. Haskell's lack of ML-style higher-order modules was a mystery to me: In spite of Haskell being more abstract and more advanced in all other ways, how does Haskell compensate for the lack of higher-order modules? |
I learned Haskell on and off for a few years, but only really got into it this past year, coming from Scala. I can confidently say that I know Haskell. Before I continue: please teach people laziness. At least 50% of the Haskell community does not understand and refuses to learn about how and why laziness works the way it does, and their programs (and libraries) suffer for it. The most unfortunate part is that laziness is to me by far one of the most useful features of Haskell. It took about three years of trying to do functional programming in Scala, and regularly encountering roadblocks, to understand exactly why Haskell is the way it is. At the very beginning of my earnest attempts to learn Haskell I had trouble with syntax. After that I had no trouble. I didn't really have problems with it once I knew the motivation. That said, there were two things which took the longest to motivate: widespread currying (as an API decision) and laziness. The first was motivated by concision and extensibility. The second was motivated by composable performance. The question Haskell answered for me was: how could I write functional code not "on the boundaries", not "as a fun experiment", but throughout programs? Haskell differed from Scala, which was previously my primary language, in being much more concise, fast and lazy. So what I had to unlearn was a lot of premature optimization and techniques related to compressing code to make it shorter. There are so many ways to abstract in Haskell that I spent a week writing code aimed at finding a nice abstraction, code which did nothing, was verbose, and was slow, before I remembered that the purpose of abstraction is to do stuff, and the code without the abstractions already did the stuff I wanted. Naive code in Haskell also often happens to be the fastest, most general, most concise, and most space efficient, which I was completely unused to. I mentally swapped The functional abstractions I was familiar with from Scala carried over well, and they became more useful. |
I assume that if some action is derived from this thread, it will be caught by collectively going over all "What was it like..." threads. For that reason I would assume that it is safe to close it. If anyone disagrees, feel free to open it again or request that it is opened. |
We’ve recently started a project to find the best way to design our tracks, in order to optimize the learning experience of students.
As a first step, we’ll be examining the ways in which languages are unique and the ways in which they are similar. For this, we’d really like to use the knowledge of everyone involved in the Exercism community (students, mentors, maintainers) to answer the following questions:
Could you spare 5 minutes to help us by answering these questions? It would greatly help us improve the experience students have learning Haskell :)
Note: this issue is not meant as a discussion, just as a place for people to post their own, personal experiences.
Want to keep your thoughts private but still help? Feel free to email me at erik@exercism.io
Thank you!
The text was updated successfully, but these errors were encountered: