It's not that hard, but it's easier to get one concept at a time. I'm less familiar with Haskell, but languages like Scheme/OCaml are routinely used to teach programming to beginners.
Also there's no need to see a dichotomy between "IRL productivity" and "CS/FP". Even if you don't use Haskell directly, ideas from FP make their way to mainstream languages, either as constructs, or libraries, or simply programming style.
Overall, the more programming paradigms you know, the easier it gets to learn new languages.
Haskell has a tendency to make every problem seem exactly the same :)
Normally types are used to indicate the set of values a variable is allowed to contain or not. And that info can be used by the compiler to detect mismatch in the code, like if a value is being assigned to a variable that doesn't match its type.
But like I said, this is all just metadata about variables and values. So what else could you track and enforce? Well you could also track that some values are never assigned to more than one variable. That would be Uniqueness types. A value of such type is supposed to always have a unique variable pointing to it. So you can't have two variables pointing to it, if you did, the compiler would throw an error.
Linear types are similar, with some small differences in the edge case. Specifically, you can cast a value that is non linear to be linear. In effect it means a value that is made linear can not have more references to it after it has been made linear, but it could have many references pointing to it from before it was made linear. Where as a value of a unique type would not allow that.
To recap, Uniqueness guarantees that a value has no other references to it, while linearity guarantees that no more references can be made to a value.
Finally you have Affine types, which are also just a small difference to the above two. One detail I ommited is Linear and Unique types will also fail if the value is never assigned to any variable. They basically enforce that a value having a linear or unique type must be used at least once. An Affine type is like a linear type that doesn't have to be used at all, thus they say it needs to be used at most once.
I'll add one more, Ownership types, like in Rust. Those are like a mix of unique and affine. In that a value with an ownership type can only be refered to by its current owner, but doesn't have to be. It's different to unique types in that the owner is free to refer to it many times, but no other owners can refer to it at the same time.
So you see, all of this is just lingo to say, could we come up with some constraints around how many references to the same values we're allowed to have. Then create a type for them so we can tell the compiler to enforce those constraints on values of that type.
Now it gets complicated to actually find a way to implement a compiler to track these types and enforce their constraints. That's where the research and challenge is. And it's also tricky to figure out how the programming language can use these and how to make them pleasant to use and not feel like annoying constraint that prevent you from doing things easily.
I appreciate you writing this out for me. I understand the 3 types you described quite clearly.
The compiler stuff I fortunately won't have to care as much about (unless I do this fulltime or go even harder core into types) but I appreciate your approach to it.
I believe learning Rust has helped me understand Haskell and the utility of even basic things like Maybe/Option types. Compared to like Go or whatever I want it plus pattern matching in every language I use now (pattern matching is another thing I gleaned from Erlang/Elixir as extremely useful).
Anyway, I'll find time at some point down the road to understand this better.
Purescript is more in line with the harder core FP or frontend Haskell I was seeking.
On another note, Rust does types and pattern matching quite well where I see that as another draw away from Haskell. But I feel like Haskell is the motherland for this stuff so might as well figure it out eventually.
But like a lot of Haskell much of this still goes over my head.
I'm so conflicted and my intuition is to leave this to the CS university types and focus on IRL productivity in my own field. But I want to invest more time into FP in the future.
I'm also technically a "frontend developer" professionally :p