(Sorry, it's just a not-so-well-known but awesome feature)
(Sorry, it's just a not-so-well-known but awesome feature)
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))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. echo "Hello World" | wc -c
let wc x:String =
x.length
"Hello World" |> wc
are equivalentYou 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).
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.
let n = 42.
Seq.initInfinite float
|> Seq.scan (fun x _ -> 0.5 * (x + n/x)) 1.0
|> Seq.pairwise
|> Seq.pick (fun (x, y) -> if abs <| x-y < 1E-10 then Some y else None)
|> printf "%f"
printf "%f" <| sqrt nWhen 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.
Now I'm hooked again.
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.
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.