I remember when I used to hear about so-called "functional programming" (I mean was I doing dysfunctional programming before? Weeeeell, I probably was). I would always come away with the sense that it was needlessly complex. Something only doctoral students were tortured into understanding while they were locked in the ivory tower.
However, since I mostly do functional programming today, I look back at what I could have told Past Me to make him understand that FP is not really intimidating or even reserved for people far-better educated than me. And offer some ways to approach it that setup success.
... or other things plucked from Category Theory. You really do not have to know that stuff to start out. One day, Future You may be brimming with confidence which is ready to be destroyed by a Monad tutorial. But for today, such things are interesting "optimizations" that you can learn about later.
It might be hard to avoid getting doused in type theory in certain languages -- I know that you know that I am thinking of Haskell right now. If I were Past Me, I would stick with ML-family languages that do not have heavy type requirements: examples that come to mind are F#, OCaml/Reason, Elm. For you dynamic-type programmers in the audience, those languages also have great type inference so you can omit most type declarations but still get type checking for free.
One really common mistake when starting FP is to try to look at everything with the same pair of glasses you used for object-oriented programming. You might try to hide data structures or add methods to data. Well, that's not really the way it works most of the time. You can look at Functional Programming as being more similar to Procedural (done right) than it is to OO. The big differences being that procedural executes side effects all along, whereas FP emphasizes making decisions first and translating those decisions into side effects at the very end.
One pervasive problem across all paradigms in the programming universe, is trying to shoehorn too many things into a Theory of Everything abstraction. FP is no different there. In fact, all the Category Theory stuff that you are so afraid of is precisely so you can use a single abstraction against otherwise very different things like a validation results and file IO -- so you can use the same functions on both. That's why I said earlier to consider all that type theory as an "optimization" that you can worry about later.
For now, be okay with observing some duplication of code (e.g. Hmm, there is List.map, Option.map, Result.map... can't quite put my finger on it, but I think some kind of pattern is happening there...) until you are pretty sure it is duplication of the exact same thing, not just something similar.
Sandi Metz said it well:
"duplication is far cheaper than the wrong abstraction"
I also allow myself to use side effects at the "edge" of a program. In a web API I define The Edge as
a bad movie from 1997 the "controller". So I might generate some random numbers or get the current date/time or read from the database in the controller. But any decisions I make based on those are in pure functions. Then the decisions that were made go back to the controller, who can turn them into yet more side effects, like saving to a database or loading some more data to use in another pure function. Reminder in case you haven't seen every other post I've talked about FP: being pure makes the decision functions embarrassingly testable and refactorable. Heck I even test all the bad things that can happen as well as the happy path.
Raise your hand if you have ever tried to write a class with two nullable properties which were supposed to be mutually exclusive. Example: either some data or an error. This is precisely what union types allow you to represent in a non-awkward way. Learn about them and use them in your data structures.
Did you know that union types are representable in OO languages by using inheritance? But under the OO paradigm it is considered an anti-pattern to do "instance of" checks on an object to get at its implementation details. However in FP it is a good practice to go through all the cases of a union type and perhaps use different functions for each one. Because the emphasis in FP is on functions and immutable data, not object-based abstractions which encapsulate data and methods. Keep that in your back pocket for your journey.
I'm going to let you in on a secret. Don't let this take away from using union types, but that category theory stuff is pretty much centered around them in particular. For now, Past Me,
do not taunt Happy Fun Ball always deconstruct union types with
match statements, and you will keep away from all that type theory. By the time you notice the similarity of it all, you may be ready to go deeper.
After falling in all the traps on my FP journey, hopefully I can point some out to you. ...And accurately speculate on what a better path might have looked like? Eh, accuracy is probably too much to ask. Oh well, I gave it my best go above anyway. :)