1. Elm is simple, so I have fewer options to choose from when solving a problem. This means I learn a few ideas really well.
2. Even thought Elm is very much about the web (as the article mentioned), it's awesome to be able to see things in your browser immediately. It's also helpful to be able to build an application without a backend. You can see your model in the same file that you see your view, which helps you more easily think about each part together.
3. Complier/Type System: Once I finally figured out Union Types, the compiler is super helpful and friendly.
4. Elm forces you to handle errors, functions that can fail, and "Nothing", all things that you have to (a) know about and (b) remember to do in other languages.
5. Lack of tutorials, documentation and libraries to rely on means less "productivity" but it forced me to really learn the language and how things worked. I had to implement OAuth without a library, read source code to figure out what a function did, and couldn't google every problem.
I'm too new to know if Elm taught me the most important things a I should know about programming, or if there are better options out there. I do know that it's really fun. As a beginner, that might be the most important thing.
Yes purists will complain about the bells and whistles it does have, and that's exactly the point.
You can learn elm and be productive in it in after a single weekend. And it's error messages should be the industry standard for language messages in any language. It's incredible how simple and accurate they are. It will change your view of what a compiler is capable of.
Not to mention it's not a far leap for people already doing web coding.
The official Elm slack #beginners channel is full of helpful people as well.
We do this at my university using the obscure but awesome Oz programming language (1). But then students (and some professors, truth be told) complain that it's obscure...
If I had to pick one, I'd say Elixir. It's like Erland with less wonky syntax. Another option is a pure scheme. But people hate on the parens (yes, it's not very smart, but people are going to do it anyway).
Pyret (2) is also made for this purpose, but that's sort of the caveat: it's a teaching language and people don't like that.
But I do think the Haskell family of languages is fantastic, and something to teach more, at least to math and CS majors.
I haven't looked into Elixir much at all, are there obvious pros to using it over an older/more established functional language like Clojure or Scala?
I got exposed to Oz by accident, in school. This programming language is so obscure and the documentation so indecipherable, that we thought it was created as a mean of torture for new students. Luckily for us, our functional programming classes were using OCaml and it was awesome.
Clearly, it's possible to do better. It's also possible to do much worse, and it is often done.
> Mozart/Oz has a lot of documentation. Many documents, papers, lecture notes, etc, and several web pages which list them. And subjects are often discussed in several documents. This page attempts to integrate the documentation, saying "for subject foo, see these n sources".
I expect the links are mostly rotted now.
The scattered fragmentation of the documentation was tolerable once you were familiar with both the language and its documents. But for new users, especially those without the Oz textbook, it was a serious barrier. Glad to hear it's now much better.
Thank you for the reminder of all this -- my anonymously-editable Oz wiki was still running, gathering unindexed spam. Static partial snapshot now. Activity moved to an official wiki a decade ago. Perhaps sometime, I'll look to see if any of its other pages, were also still linked to or used, or of possible historical interest, and restore them too. Thanks again.
Scheme was a breathe of fresh air coming from C/Pascal/Java. It was a totally different way to tell the computer what I wanted to do (although I had similar thoughts several years earlier programming my HP28s calculator in a Forth like language, then later when I started using Mathematica).
I prefer J myself. 
If your goal is to teach just functional programming, then Haskell may be too much since the language is about a lot more than just functional programming.
Scheme or a light lisp (including Clojure) is often the way FP is initially taught, since you can focus directly on the functional aspects and leave the complexities of static typing out of it. This was the tradition at MIT for a long time (maybe still is).
One reason I have learned to love teaching Java over C++ is that the language-based bugs tend to be "shallow", at least in the first few weeks. The error messages tend to be easy to interpret, and when programs crash it is easy to understand why (how to fix it might be hard of course!)
For later year students, it's fine to expect them to learn the weirdnesses of Haskell and C++, but not for a student on day one.
There is actually not that much crazy stuff you must learn early on. The problem with Haskell is that it's hard for beginners to know what stuff they should avoid.
Things have changed a bit too over the years. I've heard of folks that burned out on haskell after wrestling with Arrows, and obscure arrow operators. Also, remember iteratees?
C, in short, gives a good way to control actual hardware without having to introduce students to the complexities of actual hardware.
Python is good for teaching algorithms and OO design, precisely because it allows students to focus on the algorithm while not having to slow down the course with memory management.
In both cases, the idea is clear: Only teach one hard thing at a time, and then build.
By "C specific" I mean reading from freed variables, or going out of bounds in arrays. These bugs are horrible to find, but also don't map cleanly to the underlying machine, because often the compiler will optimise away invalid accesses, or move them somewhere weird, meaning you can't use your understanding of the real machine to understand the C bug.
Haskell obviously has its place, but it is much better used when looking at something like PL Theory at a 3000-400 level.
Racket is an educational programming language as well as now a great general purpose language.
I tried to learn Haskell three times and I always left with a bad taste in my mouth. So many paper cuts in the ecco-system aka I HATED Cabal and I know they changed it but man that this was horrible.
I kind of like Haskell but I’ve been turned off by the way some of the development is done.
There is, for all intents and purposes, only GHC. Yet everyone uses it by tuning on all sorts of special options to make it more usable. Why are they options? To remain ‘compatible’ with the ‘other Haskell compilers’ that basically no one seems to use.
It’s like if JS all defaulted to 1.0 and you had to pile on options to use any features after 1998.
It just makes things much more confusing and odd than necessary. To support something it seems like no one uses.
It will also be easier once the whole applicable/monad thing is done.
Haskell's focus is as an experimental vehicle for type system theory. If you want to teach type system and category theory, use Haskell.
Functional programming does not require Hindley-Milner type inference, and that happens to be one of the larger cognitive hurdles in Haskell. Algorithm W is a layer on top of the Lambda Calculus, not something essential for understanding it.
+1 for using Clojure to teach Lambda Calculus^h^h^h functional programming.
I can't say it better than Gabriel Gonzalez:
"Haskell is unbelievably awesome for maintaining large projects. There's nothing that I can say that will fully convey how nice it is to modify existing Haskell code. You can only appreciate this through experience.
When I say that Haskell is easy to maintain, I mean that you can easily approach a large Haskell code base written by somebody else and make sweeping architectural changes to the project without breaking the code."
You can follow along here: https://github.com/haskell/rfcs/pulls?q=is%3Aopen+is%3Apr
GHC is definitely the only widely used compiler, but there is at least one other significant one I know of: https://github.com/IntelLabs/flrc
I only use JS on the front end for website interactivity and that doesn’t tend to be very fancy.
Every Haskell book I’ve seen (even those many years old) includes bits about how you should basically always have X, Y, and Z on and you don’t want to bother developing without them.
Seems like those should have become default long ago.
I get why some of that stuff exists in C/C++ land where people use GCC, MSVC, and LLVM among others.
But Haskell is practically a monoculture.
Good to see from sibling comments this is being addressed in the next standard.
Of course, that completely flies in the face of an education system oriented towards training hordes of non-thinking peons into start positions at the job market. So, yes, it's not for everybody.
> It is without doubt the most beautiful language ever conceived.
Only if you're a masochist.
I do suspect that in the near term Idris may overtake Haskell as my favorite language to program in, though. I haven’t had a chance to sit down and learn it yet, but everything I’ve read about it so far has left me very excited.
Yet, it also has a much higher learning curve than any other language I met. As you learn and learn, your productivity improves again and again.
The learning curve also starts from a very low point. Without a few key concepts (no, not monads) the language is almost unusable.
That is probably an exaggeration, but it's definitely a problem you see in large complex languages with multiple ways to accomplish any particular task.
Which probably wouldn't be a bad way to teach Haskell, perhaps -- once one gets the general underlying form, understanding the rest is mostly just learning how the rest maps to that form.
The core of Haskell is not that complex (although there is a lot of complexity on extensions). All the learning is in how to apply it, not on understanding the thing.
It is like OOP development practices, but wider and higher.
To shamelessly generalize:
- Haskell/OCaml feels cerebral, academic, Mathematical, maybe even elitist
- Clojure/scheme has that dark-terminal screen, classic 80s vibe-
to me it feels nostalgic and quirky.
All of these will bore/intimidate/comfort/excite different student demographics in different ways, completely independently of the programming concepts that you're teaching. So I think it's important to keep in mind the aesthetic preferences of the students you're trying to catch.
I like it because the syntax is clean, it is functional and higher-order, but also has an explicit concept of references (i.e. mutable memory) and using functions with side effects (i.e. printing) is no trouble at all.
Just look at the Basis library. Safe to say it's nowhere near Racket, Scala, Clojure, Kotlin, ...
Alternatively, F#. That fixes the tooling issue pronto.
Poly/ML 5.7 Release
> print "hello\n";
val it = (): unit
"Finally, this article explains why Haskell is not suitable for my purposes: the principle of induction is never valid for a Haskell program! The problem is that Haskell is a lazy language, rather than a language with laziness. It forces on you the existence of “undefined” values of every type, invalidating the bedrock principle of proof by induction. Put in other terms suggested to me by John Launchbury, Haskell has a paucity of types, lacking even the bog standard type of natural numbers."
I've mostly been on /r/haskell and Quora, and watched talks by Haskellers though, so maybe the community is different on other platforms.
Some things Haskellers readily admit as issues with Haskell:
- the String type
- laziness (more contentious, but many people agree that this might not have been the right choice)
- error messages
- the prelude
Essentially, my experience has been that Haskellers are willing to accept that Haskell is not perfect.
I believe Elm would be better choice. It would allow to get a visual result easily (html), there is a clear convention about code formatting and the compiler errors are really friendly.
There are a ton of concepts you have to learn up front to even get started. The compiler is generally unhelpful if you've never dealt with it before. There are a lot of approaches to solving a problem and the language does not make it clear which approach is preferred when. Unless you're a masochist, these qualities can be quite off putting.
I think a language like OCaml is a good entry point into functional programming. The compiler errors are really useful. The language pushes you towards a sane functional approach. The learning curve is pretty smooth, too.
My alma mater seems to agree and FP with OCaml in the upper level CS intro course (https://www.seas.upenn.edu/~cis120/current/index.shtml).
> :t (+)
forall a. Semiring a => a -> a -> a
> :t (&&)
forall a. HeytingAlgebra a => a -> a -> a
Also good that it's missing "advanced" stuff like type-classes, built-in monad/functor/applicative & friends. Good for teaching because students will be compelled to learn to write that themselves from the ground up. It's all lambda calculus under the hood anyway, and thusly representable "hand-made from scratch".
fold (+) 0 [1,2,3]
I do think it's a useful concept, and that Purescript is an excellent, intermediate-level FP language.
The right language? Racket maybe?
For IO what you would need to learn is that all IO actions are values of the `IO` type and they can be sequenced together for guaranteed ordering using the `do` notation. That's it. No monads. We can introduce monads after we show using the same `do` notation for lists, `Maybe`s, and `IO`.
Forgetting about types for a second, can you really say that `putStrLn "hello"` is harder to understand than `console.log("hello")`? Trust me when I say this, plenty of people have taught Haskell to kids and the result has always been that they pick it up easily. Programmers from other backgrounds worry away too much of their mental capacity thinking about monads. Stop worrying about it and just hack away.
Here is a an example of a trivial operation in imperative programming that becomes a bit more complicated in Haskell: Create a function that prints everything in an array:
naive implementation in haskell (won't work):
printElements arrayOfStrings= map putStrLn arrayOfStrings
main = printElements ["Hello", "World"]
printElements  = return ()
printElements x:xs = (putStrLn x) >> (printElements xs)
main = printElements ["Hello", "World"]
It is not trivial to explain to a person why it must be done the second way... All of this and all we were doing was printing something to the console! It's too much! Monads aren't even a required part of functional programming. Haskell is not a great language to learn about functional programming.
printElements arrayOfStrings = traverse putStrLn arrayOfStrings
main = printElements ["Hello", "World"]
As I mentioned before, I would stick to the do notation syntax sugar; there's really no need to bring the symbolic operators into this:
printElements  = return ()
printElements (x:xs) = do
You guys are right on traverse or mapM though.
And as a poor analogy, a monad is also quite trivial.
A burrito is a monad. Explain this.
I would probably also offer elixir and some lisp variant. It was actually lisp that got me so interested in FP because I saw how much it was being used in AI research.
That said, I think its worth noting Haskell is the only one I've seen listed here that is pure FP. So if one wanted to really use FP, it might be worth wading through the maze like Haskell ecosystem, but I don't think for teaching.
It's one of those things where you should not use a solution to a problem until you understand what the problem IS. Otherwise you'll feel like things are complicated for no reason.
At the time and still today, I think that OCaml is a very good language to learn FP. Students that learn FP before any other programming language get it quickly, and others can compare and write both the imperative and the functional form of a given program. But as a whole, the installation is easy and uniform (which matters a lot when teaching) and the standard library sufficient for everything, as you never want to have a lot of dependencies for the same reason.
Of course, OCaml has its drawbacks: A weird syntax, terrible tooling... but you don't really see that when learning programming concepts. The only students which complained were the ones which already spent a lot of time programming before class and trollers at the same time.
How about using Lisp to teach functional programming? Lisp syntax is small, simple. You don't need to teach so much Lisp as teach with Lisp.
1. How does the course fit the overall curriculum?
2. What is the experience and maturity of the people taking the course?
3. How strong are the teaching skills of the instructor?
The density of functional features taught in a certain time period matters. A drastic change in mindset simply takes time that, I would say, is greater than a standard semester. A single semester is fine if FP is going to be reinforced, thereafter, in other courses.
Also, starting students with FP instead of imperative or OO means less to break down and relearn.
I've read numerous debates that try to define functional programming. I don't want to start another one because they're tedious. My experience is that functional programming is a change in mindset in how to solve a problem and organize code. The instructor's ability to teach matters. The time given to learn matters. Reinforcing the concepts throughout a curriculum matters.
For each point I make above, you could make a valid case for a different FP language/ecosystem. As much as I like Haskell, it's not a "one size fits all".
It was probably my favorite course I took in college, owing a lot to his outstanding teaching style. It awoke an interest in programming languages and a strange fetish for the beauty of them. I was probably the odd one out, few other students enjoyed it as much as I did. I became a slightly rabid Haskell promoter for a little while. I realize it's not great to build most things in but I think everyone should have the same experience I did with it (after learning some basic programming and gaining a working knowledge of at least one "easy" language like Java or Python, but before you've spent too much time with them and have solidified your opinions).
I tried LYAH and some other sources a few times, but was really turned off by those approaches. It wasn't until i found HaskellBook that I really started liking it.
I think a lot of it depends on the background of the person learning. I came from a strong math/stats background before I learned to code and so much of it clicked a lot better than other imperative languages.
So I'd say - no.
I especially had problems with searching for varios operators and what exactly they do. Also (despite having some experience with SML) - currying makes function definitions hard to read.
E.g. for (&&&): https://www.haskell.org/hoogle/?hoogle=%26%26%26
You can also search by type: https://www.haskell.org/hoogle/?hoogle=%3A%3A+String+-%3E+IO...
Haskell, due to its annoying insistence on pure functions, made functional programming click for me. I have seen functional style in impure languages before (Common Lisp) but I didn't have the discipline to really code that way - I only saw the downsides. Haskell forced that discipline on me, so I could also see the upsides. One significant upside is that one is forced to make functions really small, which leads to more readable and composable code.
Applying it to something that wasn't just plain 'ol boring was slightly hard, but creating soccer team logic as the final project with a pre-written GUI module was lots of fun. Before that I never thought exams that required writing actual code were a good idea, but this one pulled it off well.
It is written in a stream-of-thought literate style. Feedback welcome as issues.
Born as a non-proprietary Miranda alternative, but instructors would have to be careful to side-step various modern quirks across the libs ("SQL as a free-monadic-profunctor-optics" and such broohaha) for a similar teaching experience.
I suffered through a course in Haskell and functional programming in college, and the course material was so up its own butt about monads and type classes and algebraic data types and such, that I essentially wrote the whole thing off as academic flubbery. It didn't help that whatever version of GHC we had then gave off error messages more cryptic than C++ template metaprogramming, and it was such a cluster to have to bounce into the IO monad to just to do some intermediate printf debugging.
It wasn't until years later and exposure to .NET LINQ that it started to click and the motivations for why you would want to use functional programming became apparent.
We didn't use monads though (they weren't in widespread use back then), so we had to learn the accumulator-parameter pattern and tail recursion the hard way.
Learning my foldr's and foldl's and zipwith's gave me confidence that almost any imperative programming can be equally represented as a recursive function, which is an important lesson for someone who had only learned about traditional imperative programming and OOP up to that point.
Of course, a proper course should center around algorithms and recursive data structures where functional programming shines; it should not begin with building business application logic, for which a classic language may have a gentler ramp-up.
By that do you mean "Lisp, which is antiquated", or "a LISP which is antiquated"?
Lisp certainly isn't antiquated, but as the second oldest high level language after FORTRAN, there are antiquated versions of it (e.g. LISP 1.5).
I think the fact that strings are linked lists is great for beginners. One of their assignments is on web scraping, where they can reuse all their list based functions to solve the problem.
I am not too keen on Haskell's polymorphism for teaching beginners, and error messages are mostly useless for them. If I were teaching again, I would be recommending custom preludes with simpler types.
I benefited from the type inference/type declarations, and learning about generics explained in a non-duck-typing way, though, which I wouldn't have had in LISP.
I no longer have the exercises in code, just paper. I've yet to scan my handwritten notes and bring them to the digital era :-) This may prompt me to finally do it.
If you still want them, I can send you the scanned pdf to your mail. However, I think you'd better off with some free online course. On a cursory examination, this one seems similar to the content in my notes:
That's debatable. True, Lisp is Old. Hardly antiquated.
Fancy LISP variants would still be vastly easier to learn than Haskell, but a straightforward computer adaptation of lambda calculus would minimize the distance between theory and running programs.
I'm not familiar enough with Scheme or Clojure to tell whether they are too complex for an introductory course.
How can this be a complication? On Common Lisp, you can just choose not to use object oriented features (the CLOS system).
There are many CL libraries that do not use OOP code at all.
And if you want to use them, in CLOS a method is called exactly the same as a function; they are called "generic functions", so the syntax is just the same.
>without advanced features (and the accompanying syntactic pollution)
I don't think there is any syntactic pollution. Again, in Common Lisp the syntax is totally uniform for all the features, in fact for a beginners' Functional Programming course, he/she would only need to learn:
() parentheses for opening and closing an s-expression
; for comments
' for quoting an s-expression so it is not evaluated
#' for indicating that the following symbol
is a function name
(not needed on Lisp-1 languages like Scheme)
"" for delimiting a string
"Advanced" features don't introduce too much syntax either:
` for quoting an s-expression in a "template" way
(i.e. for use in macros)
, for escaping the ` operator
,@ for escaping the ` operator, "splicing" the
contents of a list; for example when passing a code
block to a macro.
Compare with Haskell.
Teaching fancy language features in an introductory course steals time and attention from fundamental functional programming principles. CLOS, unless thoroughly dissected as an advanced example of how far can you go with LISP, would be an even worse gratuitous distraction than macros.
Of course, "complex" LISP isn't going to be comparable with Haskell, and in a sufficiently long introductory course advanced language features might be worth teaching to increase student productivity.
Simple Scheme has been used for decades for introductory courses, both in schools and university.
An even simpler Lisp called Logo has been used with early programming education for kids.
Lots of educational material based on Scheme or Logo exists.
Only later did I click with monads and some other patterns like phantom types and such.
I think the sad part about learning Haskell is that everyone gets so up about monads while they definitely aren't the most important part but only one of many beautiful and magical parts of Haskell. Maybe if people stopped talking about monads so much and more about other parts of the language would people be way better at learning the language.
They are that small piece that makes everything fit together and work. If you ignore it, you will have many problems down the line.
Yet, you are right, they aren't all that interesting by themselves.
>> "up its own butt about monads and type classes and algebraic data types"
Well, those are some of the best things about doing functional programming in languages that can afford them.
>> "I essentially wrote the whole thing off as academic flubbery"
And maybe it was your attitude to the whole thing.
>> "It wasn't until years later and exposure to .NET LINQ that it started to click..."
So seriously, can't you find anything else that changed "years later"?
Haven't you changed? Aren't we talking about years of accumulated experience?
Also, .NET LINQ might be a cool example of what you can do with FP, there are elements of FP in it, certainly that's a monadic interface that makes it tick. But filtering an IEnumerable or an IQueryable is as interesting as executing an SQL query.
What have you learned about FP from executing SQL queries?
IMO the biggest win from functional programming is referential transparency. Automated verification (i.e. type checking) can definitely be useful on larger projects with bigger teams since it’s self documenting. That’s just my personal take on it though - there’s plenty for everyone to like.
Clojure has protocols which are probably inspired by type classes. Just like Clojure's protocols, type classes are a mechanism for ad hoc polymorphism that allows decoupling between data and the functions operating on that data.
Clojure indeed doesn't have monads, but this has to do with Clojure's culture (like all LISPs) of using macros for describing APIs for composing stuff. But those APIs aren't unified and some of the DSLs I've seen do not have a theoretical foundation, which really means they aren't reusable and some of them are flawed.
Due to its evolution and backwards compatibility concerns, some of its design shows its age as well. You can't make operations like "map" work on your own data types because it doesn't have a protocol defined for it.
Don't get me wrong, I actually like Clojure, but that the community is not using types like monads to drive their design is a flaw.
If you meant doesn't have the Maybe monad built in... why would you want that tangled up in your data? 
If you want a more typical functional language without type declarations or monads, there's SASL. It's an ancestor of Haskell, but I don't know of any implementation which runs on modern hardware. Interestingly, SASL was once used to write an operating system.
What Lisp is really missing from an FP perspective is purity. In fact, maybe a pure variant of Lisp would be perfect for teaching.
How can you even teach what purity is, if it is enforced?
"Bad things could happen, take my word for it?"
Lisps, Erlangs, and APLs all have distinct takes on what it means to be "functional".
For example, J is dynamically typed, permits mutable state, and doesn't really have first-class functions in any meaningful way. But it definitely has a functional "feel" to it (easy to compose functions, almost all operations are side-effect free, etc).
If you want to point fingers, I would be more worried about the rampant "anti-intellectualism" going on in this industry, accumulated along with other social problems (other -isms) we are experiencing, like sexism or ageism.
Look, it's fine if you don't understand, it's fine if something is out of reach relative to your current knowledge. And most often than not, the teacher is the one doing a poor job at teaching. There's a big difference in results between good teachers and bad teachers, between good books and bad books, etc. And maybe you don't need the subject in question, maybe you're fine with writing dirty Python scripts, whatever.
But dismissing work of other people as "academic flubbery" is mean and counterproductive and you can't teach people good manners — they should have learned those in their first 7 years of their life.
I'm also not inclined to fight for every beginner, I'm only fighting for those with good manners and if you'd know me, you'd know that I have open source libraries released and that I'm helping users in my free time and at great personal sacrifice. I'm actually putting my time and money where my mouth is and I've never berated anybody for not knowing something, only for being disrespectful.
The disrespectful ones can go somewhere else. I'm fine with having small and focused communities btw, instead of a big and toxic one, because life is too short to take abuse from random folks on the Internet.
When bad ideas are dressed up in academic authority, well they often have a hard time outside of academia. That's what "too academic" means. That this could be another bad idea dressed in academic authority and we'd have no way to tell.
I would really like to know why you conclude this, because it seems almost certainly wrong. SQL is a great example of a mainstream non-imperative, no-implicit-side-effect language, which is really the essence of functional programming.
That said, it is largely used in a giant procedural way most of the time, and is certainly not an ideal functional language, but the fundamentals of things like, map, filter, reduce, sort, etc. are there.
This is a very limited form of composition. It's very difficult to break a query down into a bunch of subcomponents that can be reused among groups of queries. CTEs are close, but it's really hard to achieve re-usability of a CTE unless you are stitching together strings at runtime.
Probably the closest you could get is a view, but even then if you have many views stitched together to form a query this can impact performance in ugly ways.
Generally in order to achieve the best performance and to get the most of out of the DB engine it seems like producing unique SQL for each query which is optimized for that query is generally the optimal approach.
In summary: Just because SQL is based on a few composable operations (map, filter), does not mean it is composable itself.
There are a few that are good at optimization (and in my limited experience, Haskell is one of them), but in general if you use lots of conceptually clean maps and filters, you will occasionally see cases where your performance is very bad because you don't have full control over exactly what is evaluated when, won't you? That seems like basically the same problem that you have with using views and not trusting your query planner to do things efficiently.
The best language for learning functional programming is the one that de-mystifies it. And since you can use many (most?) popular languages to code in a functional style, I'd say, take whatever language the students have been using, and teach them a few functional programming techniques with it.
I suppose the GP enforced it manually?
The fact that types cannot be statically checked doesn't mean you don't have any.
Bash only has one type, the string, and is thus statically typed.
Is Bash's type system better than say, Python's ?
That way you can concentrate learning the principles and you’ll immediately know how to apply them.
The basic principles aren’t hard anyhow - you can learn them completely in a day. The hard part is applying them and understanding the trade offs.
No, you don't. You don't even need to understand them before learning Haskell, much less before learning FP using a language which doesn't use monads as pervasively as Haskell does.
You obviously need to learn at least something about monads as you learn Haskell, but understanding them is not a prerequisite.
Asking what a monad is is like asking what an iterator is. It doesn't tell you very much what it actually does because it depends on the implementation. The iterator is just an interface. A bunch of functions that have to be correctly implemented according to certain rules.
It all first started with lazyness. FP developers wanted a new modern language developed from the ground up. It should be a pure language. The haskell developers soon realised the evaluation order of a pure language must not necessarily be fixed. Eventually lazyness was born. Lazyness was a unique and very appealing feature for a purely functional programmming language. However as soon as a haskell program had to leave it's protective shell and interact with the real world lazyness turned into a double edged sword!
FizzBuzzes were printing their buzzes and fizzes out of order! Chaos ensued and haskell developers returned back into the shell. After long years of work they have finally discovered it! A mechanism to force the evaluation order of a program to be partially sequential again! It is a new type of container that allows you to put another type inside it. However sometimes the only way to access the contained value is by giving the container a function that takes a the boxed value as input and returns another container with a boxed value inside! The value never escapes the box. And so was the (IO)monad born! You can now take two IO actions a and b and turn them into c which is a combination of a and b where the output of a is piped into b. Not only can we send messages to the outside world, we can also finally receive them!
Everyone was happy in haskell kingdom until the imperative migrants started writing monad tutorials... (including this one)
This story is fiction by the way.
As a bonus for all the wasted time. another crappy analogy: A cage inside a bird is given a machine that puts birds in cages. The regular tool called functor that only replaces what's inside the cage would give us a bird in a cage in a cage! The special tool gives us what we actually want! The tool named monad gives us a bird in a cage! No nested cages!
Better to teach how to use specific monads without using the dread m-word, and then say "You know, these all have something in common" and then talk about monads, or these days work your way up from Monoid to Functor to Applicative to Monad.