> A "function" is a "function" if it always returns the same result for the same arguments, right?

Yes. This matches the definition of a mathematical function that I gave above.

> how can I call a function which takes no arguments but which returns a value the user entered on the keyboard?

You can't. If your language allows you to write such a function then I would argue you are no longer doing FP (at least in this part of the code).

I believe that this is why many people like languages like Ocaml, F#, Scala. These are hybrid functional-OOP. You can use FP for the parts of the program that it's suitable for, and OOP/mutable-imperative for the other parts("the best of both worlds").

The purist FP programmers might claim that reading input from a keyboard is "uninteresting" and that programming is really about logic, algorithms, and computation, and therefore FP is enough for them (...in their ivory tower).

I personally am a fan of Haskell, but I don't like calling it FP, because it does allow you to write "code" that reads input from the keyboard. They still claim to be pure FP by using a loophole and saying that "getLine" is not a "function" but rather an "IO action". But to me it doesn't matter what you call it, you are still effectively allowed to write code that does I/O and mutates external stuff, doesn't matter if you call it a "function" or something else.

Of course the big advantage that Haskellers claim is that the language enforces the separation of effectful code from "pure" functions. In the other hybrid FP languages it is possible (and happens often) where you have a deep call chain of "pure" functions and then you realize you need some small side-effect somewhere, so you just add it. Haskell does not allow this at the language level, and forces you to refactor your code. In my opinion this does lead to cleaner architecture and more maintainable code in the long term.

But to me Haskell is really interesting for a different reason. I don't like to call it an FP language, because like I said, a lot of the code you write isn't really "functional". A better name would be: "mathematical oriented language". And by math I mean that the code is built using logical systems that have mathematical rules that can be reasoned about.

Going back the I/O (reading input from the keyboard): what the Haskell people have done is realized that you can actually model this behavior of user input as a mathematical model. This unlocks a type of thinking that allows you as the developer to go beyond the thinking of telling the computer: "do this, then do this, then do this, if this happens then do this, ...".

An example: the mouse-position on the screen. There are haskell libraries called FRP that model the mouse position as a "signal function" (a well-defined term they invented) that is a 2D coordinate that changes over time. You can then combine this signal function with others to create behavior such as an image that follows the mouse. You can build complete GUI applications using this approach, and the code looks nothing like imperative programming, and more like an electric circuit of different components connected together.

And that is just one example. The Haskell community has also come up with mathematical models for streams (think unix pipes) that allows you to write streaming code that is much more powerful and cleaner then what you see in other languages.

So my summary: Yes, functional programming is limited, but if we go one level deeper, we could say that the essence of FP is really mathematical thinking. And if we embrace that and run with it then we can open up entirely new possibilities.