5 ms·
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? m
by profquail 13y ago
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))
- username223 13y agoIt'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.
- codygman 13y agoWell 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.
- fleitz 13y agoImperative / shell programmers may be more familiar with |> as a pipe. echo "Hello World" | wc -c let wc x:String = x.length "Hello World" |> wc are equivalent
- platz 13y ago|> would be the flip of $ since the arg comes before the function
- dllthomas 13y agoSo equivalent to Control.Lens.(&)
- Chattered 13y agoyield 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).
- Chattered 13y agoThe function name is repeated because it's recursive!
- profquail 13y agoIn 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.
- daxfohl 13y agoYou could use `Seq.scan` to get rid of the manual recursion: 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 n
- darklajid 13y agoThank you for posting this. 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. Now I'm hooked again.
- daxfohl 13y agoNote given appropriate `MyLinqExt.Scan` and `MyLinqExt.Pairwise`, you could write this in C# just as concisely.
- darklajid 13y agoHmm.. 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.