The pedagogical downside of Haskell is that it ignores the physical reality of the machine. Physically, a computer is imperative, has mutating state, and is filled with all kinds of possible race conditions. Even after you apply the operating system, allowing processes to live together (and giving you space to define new ones), very few constraints are placed on your program and process space.
Instead of building on this reality, Haskell asserts that the starting point is not physical reality, but rather a mathematical formalism called "The Lambda Calculus", the physical machine is looked at with disdain and pity, its limitations to be worked around to provide the one true abstraction. This is the original sin of Haskell, because it is an attitude that isn't driven by a need to make a thing, but aesthetics and a peculiar intellectual dogma around building that ultimately becomes a stumbling block.
In my view, you have to respect the machine. Abstractions can be beautiful, but they are ephemeral, changeable, unreal. The danger is that these illusions become a siren song to makers who are always looking for better tools, and to these makers the abstractions become realer than the machine. Haskell's power users famously don't actually make anything with it (modulo pandoc and jekyll), and my guess is because either they find that 90% of real-world things you want to do are "ugly" from Haskell's point of view, and so are left as distasteful "exercises for the reader", or they get so distracted by the beauty of their tools they never finish.
In any event, Haskell is a road less traveled for good reason.
Brilliant write up.
> There is also a school of thought that you should start Haskell by teaching the IO monad first, but I am not convinced: in my experience, if someone gets exposed to IO early on, they will contaminate all their functions with IO. They will essentially end up writing Java in Haskell.
I don't think this is such a bad starting place. Crawling before walking. Purifying an (unnecessarily-) IO function into an ordinary function is a good exercise.
Trying to enforce non-IO from the start would be like enforcing 'no new keyword & factories only' in another language.
This is great and a lot of it rings true to my experience writing a book to teach Rust. It's basically a giant topological sorting exercise to find the optimal order to introduce syntax so that you steer clear of rabbit holes. Or you just end up drawing the owl.
For example, to implement a simple "hello world" program in Rust you have to use a macro (println!), so you can't even look for a function signature in the standard library docs to help. So you can either just say "don't worry about this for now, just trust me" or spend a whole chapter diving into macro syntax. The number of concepts you need to implement a basic program is pretty large and you could easily spend a chapter going into any of them.
Personally I'm not a fan of the approach in this post to just "lie" to people but I do find myself showing a non-optimal implementation because that's all the syntax I've introduced up to that point. Then later I show how to do it better. I know some readers just want the final answer up front though.
I wonder if there could be a (or already is) a "teaching" Prelude designed for this purpose.
One of the reasons the standard Prelude includes partial functions and specialize versions of `map` and `filter` is to support the pedagogical use-case (as far as I understand the situation). Most production applications will use a custom Prelude of some kind in order to prevent programmers from using foot-guns like `head` or make things more general in the case of `map` and `filter`.
Turns out using linked-lists for everything isn't the best idea but a lot of Haskell applications will use them because it's in Prelude.
Bit of a balancing act supporting both use cases.
I think Elm is second to none as a tool for learning FP.
It compiles quickly, the guidance offered in error messages are best in class, it's small, and the mental model is consistent.
In fact I think it's far easier to learn Elm (and also perhaps web UI development wouldn't be such a shitshow if programmers earlier in their career used Elm to build their mental model) than it is to learn:
- React
- Redux
- Immutable.js
- Lodash/Ramda
- ES${CURRENT_YEAR}
- Webpack/Parcel/Grunt/Groan/Whatever
- etc…
I've seen so many early programmers go through some React course thinking they've learned FP, and yet struggle to solve basic problems by applying functions to values.
Code World[1] is a great project that addresses a number of the problems from the article, with an eye towards using Haskell to teach children basic math and programming simultaneously. Code World directly addresses a number of the obstacles outlined in this article:
1. Using an online editor with a rich built-in library removes any toolchain problems.
2. A custom standard library simplifies pedagogically unnecessary details like Foldable
3. The custom standard library also avoids currying (f(a, b) for functions rather than f a b)
4. Custom error messages improve the feedback students get from the compiler
I would highly recommend Code World to anybody looking to teach programming with Haskell. If you want to teach Haskell in a way that fits the existing ecosystem, it's also possible to run Code World without the custom standard library[2].
[1]: https://code.world/#
I find the go pattern absurd. Which of these is easier to read:
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
or foldr k z = foldr_k_z
where
foldr_k_z [] = z
foldr_k_z (y:ys) = y `k` foldr_k_z ys
Point 11 surprised me. Not the “go” thing but the “where” syntax – I wish more languages had it!
PureScript might be worth considering, a few of the downsides listed here aren't in PS, for example: Int/Number primitives aren't overloaded, strict evaluation, the various tools like package management are easy, explicit Prelude means you are free to import foldl from Array for example.
Of course PureScript has it's own downsides not apparent in GHC
Had good experience at https://exercism.org/tracks/haskell
I don't think this article is helpful for beginners.
For someone not familiar with functional programming (but familiar with OOP/procedural), this was not easy or intuitive for me to follow.
I generally trying to avoid single paradigm languages that are trying to show me the one and only "true" way. I see no business benefits coming of of their use.
[dead]
[dead]
[flagged]
I find its syntax & idiomatic style incredibly difficult to follow, in a way nearly no other languages have been for me, including some functional languages (OCaml doesn't seem nearly as bad to me, for instance).
It's sometimes implied that those who trip over Haskell just aren't big-brained enough to understand various important concepts related to it, but I've found they're usually very easy to grasp, provided the explanation's not using Haskell examples. If all programming were Haskell, I probably never would have become a programmer in the first place. Would have taken me too long to figure any of it out, probably would have concluded I wasn't smart enough to be a programmer.
I do wonder if there are some shared experiences or common patterns to who tends to love Haskell, and those who don't. I also feel nigh-dyslexic trying to read math formulas. Human language and broadly C-family programming languages, on the other hand, seemed easy and natural to me, almost effortless to pick up. Wonder if there's a "mathy"-person versus "languagey"-person divide on finding Haskell legible.
I'm not sure it's the whole thing, but I think I've also figured out that I find algorithm-type reasoning far easier to follow and work with than equations or proofs. Like, the only way I can begin to get traction with an unfamiliar equation is to break down what each term and operation "does" to something "moving through" it—it's tedious as hell. Might be something there.