That depends on your background. As far as FP goes, I wouldn't see myself working in a FP language that doesn't have type-classes or something similar. Clojure has protocols and multimethods, Scala has type-classes based on implicits, while F# doesn't have anything like that.
> F# is looking more "clean" than Scala.
I don't know about that, I got used to Scala code. As far as the languages are concerned, I hate for instance how F# imported some language features from C# that really needed to die a long time ago, like static class members and operator overloading based on said static class members. Scala on the other hand cleaned all that crap. My problem with F# is basically that it has 2 type systems in the same language. Same problem that Ocaml has really, except Ocaml can also do some pretty cool tricks with structural typing for OOP that F# cannot.
But anyway, these issues are actually irrelevant because the choice for developers will end up being the answer to ".NET or the JVM?"
I agree that F# is not pure as Haskel and limited in comparison with OCaml and Haskel.
But the things that works in F# are working fine. In comparison with Scala: curring (by design) and tail-calls optimization are looking "more FP" in my opinion.
Also Scala does optimize self-recursive tail-calls and it's pretty easy to work with trampolines. This is a platform limitation btw, as you can't optimize tail-calls without support from the VM. Mono, the open-source .NET implementation, also has problems with optimizing tail-calls (last time I checked) and I don't know about .NET 4.5, but .NET 4 was not optimizing tail-calls on 64-bits Windows. I remember reading a blog post about them fixing it on 64-bits OS in the latest version, but it wasn't the kind of feature you could rely on in the past.
I do have hopes that TCO will make it into the JVM at some point, as there are experiments for it available as part of OpenJDK. Unfortunately the JVM moves at a glacial pace in regards to such features. This is both a blessing and a curse.
I do agree with you. Not having full TCO in a functional language kind of sucks.
and I don't know about .NET 4.5, but .NET 4 was not
optimizing tail-calls on 64-bits Windows.
It's lower level and more limited than full blown FP aware TCO and it may not catch every call pattern, but it's been there for a while.
In fact, F# is able to target previous version of the CLR (.NET 2.0, 3.0, and 3.5) and I know for a fact that they also support the 'tail.' opcode and perform some TCO (though it handles fewer edge-cases than .NET 4.0 and 4.5).
You see static String.Split and normal method Split of String objects.
First method does not belong to string objects, it belongs to String class.
String class is an object itself, so why not make this distinction more explicit?
It exactly so in Scala: classes are classes and all static members goes to companion objects. Companion objects by nature are singletones.
I think it's much more natural this way than in C++/Java/C#. Everything on its place, even singletones became elegant.
Those features [type classes,structural (sub)typing] you mention as being a problem simply aren't really missed due to other things on offer. While F# does not have type classes (non erasure has it's advantages to ease that lack) you don't really notice it as it turns out that kind of power is pivotal in a handful of cases and for that F# has these statically resolved type parameters which do a kind of static duck typing that is good enoughTM. The static overloading is not hit and the static methods are useful the way F# implements them (makes things simple, not as annoying or cumbersome as in C#).
Most of the time computation expressions and or simple abstract classes or interfaces with object expressions , occasionally coupled with active patterns are more than good enough for the kind of places type classes might otherwise be used. Personally, I try to make simple choices so that algebraic datatypes and records are all that is needed. I'm allergic to fancy code. I mentioned active patterns, they are really quite powerful - at the same level of power as multimethods (I have used them to solve an expression problem type thing). I believe that the use of Active Patterns and Quotations in F# is more common than in Scala due to choices in where power focus lie. I also find F#<->C# interop to be a bit easier than Scala<->Java interop for the same reason that C# -> F# objects are basically injective while Java -> Scala is only a subset.
I also think F# is more functional than Scala. Scala is supposed to be something different: a successful melding of OOP and functional. And it is the best at that I have seen. It succeeds on this better than the next biggest contender: F#. F# is more typically functional, using the usual Hindley Milner Inference and sharing a core with OCaml but with significant whitespace. So it can be very succinct. Typically functional idioms like algebraic data types, Piping, point free, currying and combinators is more natural to F# than Scala's more OOP way.
There are a number of things that Scala does naturally that are cumbersome in other languages because of how it manages to meld a powerful combination of orthogonal features. To use Scala as just another functional language is to miss its power. Those who criticize OOP have not used a language that does it right. Abstractly, in a simplified categoric setting, we can consider Abstract types (objects as an aproximation as coalgebras) and FP (algebraic data types) as duals of each other. A proper unification of the concepts gives something more flexible than either. I think Scala comes the closest. Sure you can be 100% functional in it, or replicate Java but to call it one or the other is to make the same mistake as to say that light is both a wave and a particle and think you understand what that means.