Nathan, On 8 September 2015 at 15:58, Thomas Koster <[email protected]> wrote: > F# appears to eliminate tail calls to self by program transformation > where it is trivial to do so, but relies entirely on the CLR for > optimizing tail calls in general. This would mean that the stability and > reliability of programs written for the CLR in F# is uncertain, and that > debug builds of F# programs are always unreliable. I would want much > stronger guarantees about space complexity if I were to seriously > consider F# as a programming language for paid work. > > So if anybody has used F# in the real world, what's the story?
On 14 September 2015 at 18:06, Nathan Schultz <[email protected]> wrote: > IIRC, as you said, for most tail-end recursion, you'll find that the IL that > F# generates is actually a simple loop with a mutable variable. In cases > where there's continuations involved or more complex scenarios with multiple > recursive functions, F# will automatically provide the CLR with the .tail > instruction. Work has gone into the CLR to better support tail end > recursion, and there have been lots of fixes in recent versions (e.g. going > back a couple of years, there used to be scenarios where the JIT would > ignore the flag, but have been fixed). > > I've never run into an issue myself, although infrequently I have heard of > corner-cases that still pose issues (e.g. > http://blogs.msdn.com/b/dotnet/archive/2015/07/28/ryujit-bug-advisory-in-the-net-framework-4-6.aspx). > However, I've also heard it said that when it comes to tail-end recursion F# > is in a better place with the CLR than Scala is with the JVM. And both are > used in production even in financial institutions. > > Given that I (rarely) still run into other bugs in the .Net framework with > C#, I don't see this as anything different; testing (including on different > platforms) is a necessary part of application development, and with F# it's > no different. Thanks for your response. I readily believe that the JVM is a worse place for functional languages than the CLR. But both seem to share the same weakness when it comes to implementing functional languages: they both support only one evaluation strategy, namely the stack-based, strict, call-by-value evaluation strategy of the curly brace langauges (and their predecessors). The opcodes needed to implement other strategies efficiently are missing. I am starting to see that I may have over-estimated the number of ways space leaks caused by tail calls can creep into an F# program. But since F# uses a strict evaluation order where tail call elimination is absolutely necessary to avoid excessive space usage, the discretionary nature of the ".tail" opcode prefix still makes me uneasy and I would rather not have to write tests to verify the correctness of the F# compiler, let alone the JIT compiler. So for now, for me, F# remains just an intellectual curiosity. -- Thomas Koster
