https://kurser.ku.dk/course/ndaa09013u/2023-2024
The course teaches Haskell, Erlang and Prolog over half a semester (7.5 ECTS).
It mainly focuses on Haskell (7 weeks?) and covers Monad/Applicative/Functor bottom-up (i.e. you define your own, rather than use mtl/transformers), property-based testing (QuickCheck, generators, shrinking), parser generators (ReadP, minus points for parsing whitespace ambiguously). It is the 1st MSc course, so those who didn't have an FP-heavy bachelor's degree will have quite a shock. The Haskell part of the exam is writing a parser and interpreter for a non-trivial DSL.
The Haskell part already blasts most people. Then comes the Erlang part (3-4 weeks), where you learn about OTP, supervisors, process hierarchies, map/reduce, or similar problems. I remember one exam was implementing a quad tree where each level in the tree was controlled by a process.
The third part is Prolog, of which only a week of the course is dedicated to. While Prolog is a little mind-blowing in itself, the fact that it's only for one week also means the Prolog part of the exam is typically only a small set of exercises, where the Haskell and Erlang parts can be hard to complete given the allocated time.
When I took the course, I started learning Haskell in the summer break before the course started. Having two months of Haskell under my belt meant I survived the course quite fine (and ended up TA'ing it several times). But I saw lots of people way smarter than me (some of whom are now CS professors) struggle quite a lot with the pace and learning style.
Definitely the hardest course. To some unreasonably.
Moreover in the same class we also had exams, in one exercise you had to write more SIMD code in x86_64 (over images, strings of utf-8 characters, etc.) this was all in paper and no reference was allowed except the Intel Manuals; that was just one exercise there were more in systems programming, etc.
I also had a bad time with Prolog and Haskell in a Paradigms class though those exercises were a bit more bite-sized and streamlined.
Non-programming wise, I'm having the hardest time right now with a Numerical Methods class which involves a lot of proof-based linear algebra, induction over matrices, etc. I also had a bad time with a Logic and Computability class.
Spoiler, I did not succeed at that, but neither did most of the class.
My prof maintained a notable SML compiler, so the language we developed our compiler for was an SML style language that was statically typed, type inferred, and functional (very capable language). From parsing, to type checking, to code gen, to optimization, every project in that class was so much fun. I hate a lot of late nights with four or five tmux windows open tracking down errors, but I don't regret any of those. Aced everything in that class except the exam on parser algos (did not study as well as I should have).
That class made me realized that I can probably write any code I needed to, assuming I had some reading on the existing domain. Huge confidence booster.
[1]: https://merlot.usc.edu/cs402-s23/ [2]: https://pdos.csail.mit.edu/6.824/
The first was to implement a search algorithm that combines binary search and interleaving search which was pretty easy.
The second was to implement a prime number generator that generates >=1024-bit prime numbers without relying on bignum library. I miserably failed at this, been meaning to revisit this (over 15 years since).
The third was to implement a huffman encoder/decoder and an lz77 compressor/decompressor. Huffman was easy, but I found lz77 pretty difficult to implement efficiently (poor choice of data structure for the dictionary and phrase search on my part). I got a very minor deduction for the implementation not being quick.
Despite not doing well I hold the course in high regard.
The OCaml part is free, well structured and does not take long to complete.
It wasn't one of those "memorize the textbook and you'll be fine" type of classes. It was a "do a bunch of independent research and figure a whole lot of things out for yourself" type of class.
It's ofcourse, about low level programming, but since, the lower levels underpin the higher ones, for me the most useful thing was this book.
It was a super challenge for me personally (no degree in computing or anything), and working through it i felt more things click than any other resource i tapped into before. I feel i understand much better in any language now, what actually happens on the PC, and how to go about investigating what happens if i do not. (finding specifications, isa documents, documentation on interpreters of scripts etc. etc., learning to read code/sources.)
That being said, do you have a specific direction in which you want to improve? Because this obviously leans towards a specific flavor of programming, where it's maybe not as useful if you want a different flavor. I know many good/professional programmers who know nothing of this stuff and are really really good in their own domains.
Networking: Not really "difficult" concepts, but the teacher had a chip on his shoulder. The programming assignments were "fun challenging", and I think if the course was taught at a slower pace, it would have sunk in better.
Assembly: I personally didn't struggle too much, but a lot of the class did. My secret was that I had read a little bit about assembly programming in high school, and realized that I had to force myself to follow "structured programming patterns." (If true goto true else goto false.) (I also programmed with a lot of GOTOs as a kid, so I knew enough not to make a mess.) I remember showing one of my high-score assignments to another kid in class, it "clicked," and they told me that if they realized that they could make their code kinda look like normal structured code it would be much easier.
(Also, I forgot that I really, really struggled with the first assignment, which was to write "hello world" using the DOS debugger. That was the angriest I ever got in college.)
As far as "not limited to programming courses":
Foundations of Computer Science: This was difficult because of the professor. They really didn't click or empathize with the class. Most of the class was about regular expressions. They never made sense to me, so now I just have ChatGPT write them for me.
Compilers: I really, really enjoyed the homework, but again, difficult because of the professor. It basically picks up the theory from Foundations of Computer Science.
One thing I noticed was that theoretical CS classes at my school had professors who didn't really understand the students and their goals. Most of us were targeting software engineering careers: The professors would often get us lost in the theory and not bring it back to concrete terms.
Automata is a good one to give you some understanding of how things work 'underneath'. The different algorithm ones are good because by implementing algorithms from scratch you learn how they actually work and that helps inform when you'd choose specific ones. I find that a decent background in algorithms is what really separates the self taught folks from the college educated ones.
Database programming was kinda tough, at least the theory side of it, because relational algebra and relational calculus are complicated and the whole normalizing databases during the design stage of things.
Lots of Turing Machines and constructing proofs. I'm not sure I would have passed if it wasn't for my friend who worked with me on the homework.
If you want to learn about applying your skills more successfully, look into an area where you think you'll be working. Most people don't graduate with a CS degree and start working on compilers. I worked at a network vendor where we made firewalls/routers, a lot of our programmers didn't have a clue how customers implemented our products in the real world. In that case, taking networking and security courses would be beneficial.
What's great about it vs other courses is you had to understand an extremely complex thing and learn to modify it, instead of building something from scratch. In the real world, many things are not documented or misdocumented, so it's a vital skill to be able to understand how something works from the code.
Programming is something you will get better at as you do it, so I wouldn't worry too much about it. Instead I would look for computer science courses that interest you and a course outside of comp sci that requires a lot of writing. Although technical writing is probably what you will be mostly doing, consider taking a creative writing or a critical reading course.
Most work in terms of hours spent: compilers (you had to write one from scratch)
Hardest due to inherent difficulty of the material: theory of computation. Turing Machines and the Halting Problem and such weren't too bad (well, duh) but some of the more advanced stuff was pretty challenging, at least to me.
Hardest due to the material being a collection of bizarre recipes and jumping all over the mathematical map: tie between an undergrad numerical methods course and a graduate modeling and simulations course. It wasn't conceptually difficult to write the code, but understanding exactly why it worked was a different story. I've never been good at memorizing stuff unless I understand how it works (advanced statistics suffers from a similar glut of "magic recipes", in my experience).
Edit: the compilers class was the one that's proven to be the most useful over the rest of my life. I've written specialized parsers and so on a bunch of times.
I've never used the stuff from theory of computation again, nor can I imagine that anyone would who wasn't a researcher in that area.
I could see numerical methods being useful if I did a lot of down and dirty work with the physical world, but I mostly haven't done that..
Hardware security (implementing rowhammer in JS powered by WebGL)
These were by far my hardest courses. One course that comes somewhat close is a course in Buddhism (meditatie en paychologie - meditation and psychology). The issue is that I didn’t have prerequisite knowledge. The psych part was easy. Reading a 1000 year old Burmese text on Buddhism/meditation at that time had so many crazy traps that it was just fascinating how wrong I interpreted that text.
Easiest course that I took: social psychology
Best course that I took: a teacher that said “I am too lazy to teach. Just make a cool project.” I taught myself iOS development and made an iPhone app that led to a job for a year creating an iPad app
All at the Vrije Universiteit Amsterdam
Most fun course: technology & games. Creating a game with unity3d and publishing a paper, that was fun. This was at the Universiteit van Amsterdam. The course doesn’t exist anymore sadly
Hardware security (implementing rowhammer in JS powered by WebGL)
At the Vrije Universiteit Amsterdam
These were by far my hardest courses. One course that comes somewhat close is a course in Buddhism (meditatie en paychologie - meditation and psychology). The issue is that I didn’t have prerequisite knowledge. The psych part was easy. Reading a 1000 year old Burmese text on Buddhism/meditation at that time had so many crazy traps that it was just fascinating how wrong I interpreted that text.
Easiest course that I took: social psychology
Best course that I took: a teacher that said “I am too lazy to teach. Just make a cool project.” I taught myself iOS development and made an iPhone app that led to a job for a year creating an iPad app
Edit: noticed that it’s not just about programming. Then it’s complex analysis and theoretical physics at MIPT. Most computer science problems felt simple compared to that stuff.
https://ocw.mit.edu/courses/6-001-structure-and-interpretati...
[1]: https://en.wikipedia.org/wiki/Abstract_interpretation
It was much more interesting/useful the other compiler class I took which actually had me create a parser+compiler for a made-up language. Still somewhat challenging to think in that way, as it's not the usual way to process data.
I really had to work for that class, but the payoff was tremendous.
The Pavlov course is good.
A course being challenging is not a good indicator of its quality I think.
I'm not sure I would call it the most challenging class, but it's the one where the most amount of people failed to learn anything. If I had to guess then 90% of the students (or more) ended up not being able to do anything with prolog.
I haven't seen any other class that had such an abysmally low rate of successful learning. I think the only knowledge most people took away from this class is to not use prolog.