Functional programming is a different paradigm from Object-Oriented programming (a different mindset, and a different way of thinking about programs). You have begun to realize that here is more than one way (object-oriented) to think about problems and their solutions. There are others (procedural and generic programming come to mind). How you react to this new knowledge, whether you accept and integrate these new tools and approaches into your skill set, will determine whether you grow and become a more complete, skilled developer.
We are all trained to handle and are comfortable with a certain level of complexity. I like to call this a person's hrair limit (from Watership Down, how high can you count). It is a great thing to expand your mind, your ability to consider more options, and have more tools to approach and solve problems. But it is a change, and it pulls you out of your comfort zone.
One problem you may encounter is that you will become less content to follow the "everything is an object" crowd. You may have to develop patience as you work with people who may not understand (or want to understand) why a functional approach to software development works well for certain problems. Just as a generic programming approach works well for certain problems.
Good Luck!
You seem to be drawing a line between declaring things and instructing a machine. There is no such hard-and-fast separation. Because the machine that's being instructed in imperative programming need not be physical hardware, there is much freedom for interpretation. Almost everything can be seen as an explicit program for the right abstract machine. For example, you could see CSS as a rather high level language for programming a machine that primarily resolves selectors and sets attributes of the thus-selected DOM objects.
The question is whether such a perspective is sensible, and conversely, how closely the sequence of instructions resembles a declaration of the result being computed. For CSS, the declarative perspective is clearly more useful. For C, the imperative perspective is clearly predominant. As for languages as Haskell, well…
The language has specified, concrete semantics. That is, of course one can interpret the program as a chain of operations. It doesn't even take too much effort to choose the primitive operations so that they map nicely onto commodity hardware (this is what the STG machine and other models do).
However, the way Haskell programs are written, they frequently can sensibly be read as a description of the result to be computed. Take, for example, the program to compute the sum of the first N factorials:
sum_of_fac n = sum [product [1..i] | i <- ..n]
You can desugar this and read it as a sequence of STG operations, but far more natural is to read it as a description of the result (which is, I think, a more useful definition of declarative programming than “what to compute”): The result is the sum the products of [1..i]
for all i
= 0, …, n. And that is far more declarative than almost any C program or function.
Best Answer
There is an inherent difference in Haskell and F# semantics. In Haskell, a function call does not perform any real calculation, but allocates a heap object known as a 'thunk'. It is perfectly okay for a thunk to have a link to itself or another thunk. However, in F#, a function call is an actual call, making expressions like
let x = 1 : 2 : x in x
invalid - as it requiresx
to be constructed before1 : 2 : x
is constructed. However, it is still more or less reasonable definition for infinite list, some way to define it should exist. Here lies roots forrec
. If you want more, search and read for operational semantics for SML and Haskell - it is different.