Now here's the same example in F# (a functional language); it compiles into IL similar to that produced by your C# code. Which do you find more readable?
module Program =
let n = 42
let rec sqrtGuesses x = seq {
yield x
let next_x = 0.5 * (x + (float n / x))
yield! sqrtGuesses next_x }
sqrtGuesses 1.0
|> Seq.pairwise
|> Seq.pick (fun (x, y) ->
if abs (x - y) < 1E-10 then Some y else None)
|> System.Console.WriteLine
System.Console.WriteLine (sqrt (float n))
When I saw the original version in F# I thought "I think I can do better" after a long absence from using F#. When I got back to my laptop and searched for the to-be-improved snippet I saw yours.
Hmm.. No. :)
I guess that's discussed all over the thread here. I do like C# in general and agree that it can be used in a functional style, but 'just as concisely'? Can't agree with that.
Needs the boilerplate (class definition, Main vs. .fsx for example), most keywords/methods seem to be longer (especially the Linq ones, SelectMany, FirstOrDefault etc) and there's no inherent way to build a pipeline as in "no |>".
Obviously you can write quite similar code in C# and I would agree that C# doesn't make it especially hard, is even a roughly decent language for that sort of stuff.
Still, the F# snippet looks a lot nicer to me.
Which leads to .. Just a matter of preference, ymmv etc - there's no claim of superiority here.
It's a wash. To understand that thing you posted, I'd have to look up what the exclamation point does to "yield", why adding it forces you to repeat the function name, and whether those "|>" sequences are typos or some weird operator. The other version has some random StudlyCaps, I have to look up. Meh.
Well it's only a wash if you are familiar with one and not the other (and that's the case IIUC). You don't intuitively know what the C# version does either.
For future reference "|>" like "$" in haskell is just short hand for a start and end parenthesis and end of expression or next instance of "|>" or "$".
So in Haskell:
sum $ filter (> 2) [0..10]
is a less noisy way of saying:
sum(filter (>2) [0..10])
About the exclamation points, I believe it causes it to evaluate and has to do with ensuring the expression is evalauted. At least that is the case in haskell.
yield and yield! are both keywords used in sequence expressions. To compute a sequence of type seq<'T>, you can use a sequence expression, in which the yield keyword takes a value of type 'T, and adds that value to the computed sequence, while yield! takes a value of type seq<'T> and appends that value to the computed sequence.
You also have keywords "return" and "return!" for F#'s version of monads. In Haskell, "return" is just a function, while "return!" is not needed (though I wish it was present in Scala).
In F#, yield emits a new element in the sequence (just as in C#), while yield! emits all of the elements from another sequence you provide. This effectively allows you to "splice" sequences together, or create a new sequence by prepending/appending some elements to an existing sequence.
As another commenter mentioned below, yield! has nothing to do with repeating the function name -- the name is repeated because it's a recursive function (i.e., a function which calls itself). So the sqrtGuesses function produces a sequence which emits (yields) the value it's given (x), computes the next value of x, stores it in the variable next_x, then emits all of the values in the sequence produced by calling sqrtGuesses for the next value of x (next_x).
The |> is called the "forward pipeline operator" in F#, and it's very simple -- whereas you normally call a function f with a value x by writing f x, you can swap the order of the arguments with |> to write x |> f. This effectively allows you to write nested function applications without all of the parentheses: f(g(h(x)) can instead be written x |> h |> g |> f or h x |> g |> f or whatever.
For those complaining about the verbosity of c#, here is an alternate c# representation:
public static void Main()
{
const int n = 21;
Observable.Generate<double,double>(1, x=>true, x=> 0.5 * (x + (n/x)), x=>x )
.Scan(new {prv = 0d, cur = 0d}, (prev, curr) => new {prv = prev.cur, cur = curr})
.FirstAsync(_ => Math.Abs(_.cur - _.prv) < 1E-10)
.Select(_ => _.cur)
.Subscribe(Console.WriteLine);
// this is just to compare values, so is not part of the solution
Console.WriteLine(Math.Sqrt(n));
Console.ReadLine();
}
That's is, everything you need to run the program (technically one line of code, line breaks are for readability). And its non-destructive, has no side effects and is pretty easy to read.
I would never argue that c# is a 'proper' functional language, but the poster above wrote in the style of idiomatic java, something a lot of c# devs do. I don't think c# has an 'idiomatic'. It is very flexible, and while never truly functional, can be also be used like a scala.
Having someone re-write my 7 line Haskell program into 40+ lines of C# is the best argument I can think of for why it's worth learning a functional programming language ;)
Downvoted. I think the ";)" indicates pretty well that this is tongue in cheek. I wouldn't draw any conclusions about the Haskell community, which is very nice, from this.