But I never see contrived real-world examples, those that really show how things are different from imperative or procedural programming. I want to see how you use stateless functional programming to control a garage door actuator. Or how you model a Car which can have their doors open or closed either by the class itself or external actors. How do you receive UDP packets, including a buffer implementation that is able to sort out-of-order packets and send retransmission requests for missing ones? That kind of stuff.
Are there any resources that show these kind of "here is a list of problems, how they are typically solved, and how you could solve with FP" style examples?
EDIT: This message was actually to say thank you and that TFA is an awesome resource to help understand how the Iterator methods work! And then I got lost in my semi-rant and forgot to actually say thanks :)
It shows how a functional approach can embed much of the domain logic into the types used. They are so simply expressed in F# that non programmers can understand what they say about the problem domain.
The book is selling me on the idea that Functional programming could do a better job in CRUD style business apps.
It doesn't cover a lot of good topics in the book, but it might whet your appetite.
This book (along with Domain Driven Design made Functional, mentioned elsewhere) are both great resources for getting introduced to “useful” functional programming.
I'm not sure why you'd want to see contrived examples, but the reason to focus on map, filter etc is that this is where it starts, and this is what functional programming _is_, transforming sequences of values with pure functions, rather than keeping a lot of state and change it imperatively.
How to write a real world program with functional programming is a later question, and pointless until you understood the basics. All your examples also include a bunch of concepts and data that A. can't be purely functional and B. will vary widely between programming languages, so they are very poorly suited for an introduction.
Although I must say, my examples are actual instances where I tried to put the shallow learning I had done about FP and failed spectacularly at doing so. It was no doubt due to my ignorance and lack of experience with FP, but maybe also there is a part of me not working with problems that lend themselves easily to a FP approach...
That is way too much for me to put into a single comment, but the most common approach is to split your program into "pure" and "impure" parts and then model all of your interactions with the real world in a way where the "pure" part of your program becomes an "interpreter" that deals with the pure representations of real-world events.
A common pattern for doing this (but by no means the only one) is using Free Monads.
I guess it's a little easier with OOP, but it isn't very clear to me how "polymorphism" helps me open a garage door, or even achieves it's stated goals. I guess I can at least understand that now I can open any door by calling door.open() or something. Of course it gets much worse when you graduate and people tell you OPP is overhyped, there's too much abstraction here. Then you think "I thought the abstraction was good". Don't just create a garage door, create a door factory! Then you realize you don't have a good defense, and that you don't understand as much as you thought. You were never taught to design programs pragmatically. You just have to figure that part out on your own.
I can understand how mutable state causes problems and would be a good thing to avoid where possible. There's really not much needed to convince even a moderately experienced programmer, of the power of pure functions. It doesn't feel that far off from the OOP example.
Have something nullable? Stick it inside `Maybe` and map it.
Have a side effect in `IO` and want to manipulate the result? Map it.
Following that, look at monadic binding. It's basically flat mapping.
From here you can start to see how programs can be composed in languages like Haskell. You have these foundational typeclasses and you sort of just connect all your functions together with them until you're left with one big expression in `main` which is your application entrypoint.
But I’d say in general that FP is mostly just an alternative to OOP, maybe even leas than that, not a complete paradigm for writing complex programs. At least if you use a mainstream language, then FP is probably something you do pretty locally.
The only caveat is in I/O mechanisms. An IO monad is one way to safely manage IO, but it is not the only way.
One things I’ve found enlightening is when participating in Advent of Code exercises, watching how people are able to solve problems using functional languages. While I may not always grok the solutions in their entirety I’m often impressed by the compactness and elegance.
My only complaint about FP, and Linq in particular, is that it can often result in suboptimal execution when you have preconditions that Linq isn’t aware-of, such as a known input size, or known uniqueness of some key-property - and there isn’t a way to supply hints. And C#’s weak support for contravariance, aieee. Still lightyears ahead of Java though :)
A function using the IO Monad looks like regular imperative code except for the type signature of the function which indicates that the function side effects and thus can only be called by other functions that side effect. Pure functions cannot call a side effecting function. This helps in isolating side effects and capturing it in the type signature of functions.
Plenty of examples here
Functional programming is not stateless programming. Rather it captures any state changes in the type signature. An explicit example of it would be the state monad.
At which point you are happy with "functional" is up to you. Its not all or none.
Here is an educational bulletin board website built with Haskell:
So a functional component in react using hooks is not pure. You can translate it into FP with a bit of magic, but requires a context. The line is not that distinct at all.
Of course you then have a mixture of both, which many if not most modern languages have. Pure FP can be expressed in a language that supports mutation anyway, it's just a matter of how much first class support those features have. Languages like Haskell I think go so far into the abstracting of time, that they reached around and achieve something like mutation based syntax, except there is a tower of abstractions working under the hood, ensuring that it's still timeless equations which result in side effects.
Functions like ‘map’, and ‘fold’, and ‘zip’ are; but Iterator is not the term to describe such function.