I know that type classes are not available in F #, but is there a way to use other language functions to achieve such extensibility?
I don’t believe that, no.
If not, how close can we get to solving the problem of expression in F #?
The problem with the expression is to allow the user to expand your library code with both new functions and new types without having to recompile your library. In F #, union types make it easy to add new functions (but it's impossible to add new union cases to an existing union type), and class types make it easier to output new class types (but it's impossible to add new methods to an existing class hierarchy). These are two forms of extensibility required in practice . The ability to spread in both directions at the same time without compromising the static type is just academic curiosity, IME.
By the way, the most elegant way to provide such extensibility that I have seen is to sacrifice type security and use the so-called "rule-based programming". Mathematica does this. For example, to compute a symbolic derivative of an expression that is an integer literal, variable, or append, you can write in Mathematica as follows:
D[_Integer, _] := 0 D[x_Symbol, x_] := 1 D[_Symbol, _] := 0 D[f_ + g_, x_] := D[f, x] + D[g, x]
We can modify the support for multiplication as follows:
D[f_ g_, x_] := f D[g, x] + g D[f, x]
and we can add a new function to evaluate the expression as follows:
E[n_Integer] := n E[f_ + g_] = E[f] + E[g]
For me it is much more elegant than any of the solutions written in languages such as OCaml, Haskell and Scala, but, of course, this is not a safe type.