3 ms·
F# is a big language, it is a ML multi paradigm language that interoperates with C# so there is a lot of necessary complexity and many ways to do the same thing
by cjbgkagh 2y ago
F# is a big language, it is a ML multi paradigm language that interoperates with C# so there is a lot of necessary complexity and many ways to do the same thing. A strong benefit of this is the ability to create a working functional paradigm prototype that can iteratively be refined to a faster version of itself by hot spot optimizing the slower parts with equivalent highly mutable functions while staying within the same language. Similar how one would use python and C++ and over time replace the python code with C++ code where performance is important.
For the specific case of C# use of await it is unfortunate that C# didn't design this feature with F# interop in mind so it does require extra steps. F# did add the task builder to help with this so the 'await' is replaced with a 'let!' within a task builder block.
let getById(id:int) : Task<string> = failwith "never"
let doWork(post:string) : unit = failwith "never"
let doThing() = task {
let! post = getById(42);
doWork(post); }
Alternatively the task can be converted to a normal F# async with the Async.AwaitTask function.
let getPostById1(id:int) : Async<string> = async { return! getById(id) |> Async.AwaitTask }
let getPostById2(id:int) : Async<string> = getById(id) |> Async.AwaitTask
let getPostById3 : int -> Async<string> = getById >> Async.AwaitTask
- neonsunset 2y agoIt is best to just use task CE full-time unless you need specific behavior of async CEs. The author of the original comment, however, does not know this nor tried verifying whether F# actually works seamlessly with this nowadays (it does). Writing asynchronous code in F# involves less syntax noise than in C#. None of that boilerplate is required, F# should not be written that way at all.
- cjbgkagh 2y agoF# is a big language so I think it is to be expected that beginners will not know these things. I don't think the fix is to simplify F# we should just understand that F# is not for everyone and that is ok.
- neonsunset 2y agoThis is perfectly fine, but I think it's better to be unsure about specific language feature than confidently state something that is not correct (anymore). Personally, I'm just annoyed by never-ending cycle of ".NET is bad because {reason x}", "When was this the case?", "10 years ago", "So?". Like in the example above, chances are you just won't see new F# code do this. It will just use task { ... } normally.
- shortrounddev2 2y agoI understand that you CAN do this, I'm saying that it makes your code look like shit and takes away some of the elegance of ML
- neonsunset 2y agoPlease stop insisting on this. Task CE exists since F# 6.0 and handles awaiting the CoreLib Tasks and ValueTasks without any ceremony.
- deleted 2y ago[deleted]
- cjbgkagh 2y agoAre you saying you prefer Ocaml to F# or C# to F#? Your example was indeed inelegant but it is also poorly designed as you take 4 lines to reproduce a function that is already built in, people can poorly design code in any language.
- shortrounddev2 2y agoI'm saying that I wish computation blocks looked better in F#. Instead of: let foo id = async { let! bar = getBar id return bar } I would prefer let async foo id = let! bar = getBar id bar or even something like let async foo id = getBar! id So that computation blocks don't feel like you're switching to an entirely different language. Just wrap the ugliness in the same syntactic sugar that C# does. As it is, C# can achieve arrow syntax with async methods more elegantly than F# can: async Task<string> foo(int id) => await getBar(id); This, to me, is also part of a larger problem of F# introducing unique keywords for specific language functions instead of reusing keywords, like member this.Foo = ... and member val Foo = ...
- cjbgkagh 2y agoYour criticism is rather incoherent and it is difficult for me to make sense of it. You don't even have to use the computation block for that and can use the built in functions as I mentioned earlier and gave 3 examples of. You're both complaining about extra keywords while trying to make the case of adding yet another one. Thus your complaint boils down to F# not picking the exact keywords that you like - that the language is not specialized to exactly how you want to use it. In language design there are always tradeoffs but I'm unable to see how your suggestions would improve the language in the general case or even in your specific case. Computation expressions are a generalized concept which are there to add the exact kind of syntactic sugar that you're after. It's better than C# in that you can create your own as a first class concept in addition to using the built in ones. It's there for the exact purpose of creating mini-embedded DSLs, the very thing you're complaining about is the exact point of it. F# is not for everyone, nor should it be.