I wrote some queries in C# using LINQ. After a while, I started using Haskell a little bit, which is a functional programming language (a not so popular one), and for me it
It is true that C# has gained some aspects of functional programming. First and foremost is the lambda statement, implemented as an anonymous delegate. You now no longer need to define a method as belonging to an object, and you can define a method in a similar fashion as any other variable. This allows for many functional-type constructs:
var mult = (a,b)=>a*b;
var square = (a)=>Math.Pow(a,2);
var multandsquare = (a,b)=>square(mult(a,b));
//None of the above give a lick about what a and b really are, until...
multandsquare(5,3); //== 225
The basic paradigm of functional programming - that basically anything you can tell a computer to do can be told in terms of higher-order functions - can be applied to C# programs, especially now that C# actually has higher-order functions. The compiler will force you to have at least one class with at least one public main method (that's just how OO works), but from that point you can define pretty much everything only in terms of functions (def: a subclass of "methods" that take N parameters and produce 1 output without "side effects") instantiated as lambdas.
Linq does have some functional structure. Basically its method-chain paradigm is an example of monadic processing, which is how sequences of operations are structured through operation encapsulation in functional languages (and now in C#). Calling a Linq method on an IEnumerable returns another IEnumerable, which is really a different concrete class which contains a handle to the source Enumerable and some lambda to perform. You can replicate it in a functional language very simply; it's a tuple of the source (itself a tuple of the current element and everything else) and a function to perform that transforms the source tuple into the result, one element at a time (which in Linq, as it would be implemented in a functional language, is a nesting of some operation into a defined "rollup" function). Call a method that must produce an actual answer (a concrete typed result), and all these functions are evaluated sufficiently to produce the desired result.