Я знаю, что классы типов не доступны в F #, но есть ли способ использовать другие возможности языка для достижения такого рода расширяемости?
Не верю, нет.
Если нет, то насколько мы можем приблизиться к решению проблемы выражения в F #?
Проблема с выражением заключается в том, что пользователь может дополнить код вашей библиотеки новыми функциями и новыми типами без необходимости перекомпиляции библиотеки. В F # типы объединения упрощают добавление новых функций (но невозможно добавлять новые случаи объединения к существующему типу объединения), а типы классов облегчают получение новых типов классов (но невозможно добавлять новые методы в существующую иерархию классов). , Это две формы расширяемости, требуемые на практике. Возможность расширения в обоих направлениях одновременно без ущерба для безопасности статического типа - это просто академическое любопытство, IME.
Между прочим, самый элегантный способ обеспечить такой вид расширяемости, который я видел, - это пожертвовать безопасностью типов и использовать так называемое «программирование на основе правил». Mathematica делает это. Например, функция для вычисления символической производной выражения, являющегося целочисленным литералом, переменной или сложением, может быть написана в Mathematica следующим образом:
D[_Integer, _] := 0
D[x_Symbol, x_] := 1
D[_Symbol, _] := 0
D[f_ + g_, x_] := D[f, x] + D[g, x]
Мы можем модифицировать поддержку умножения следующим образом:
D[f_ g_, x_] := f D[g, x] + g D[f, x]
и мы можем добавить новую функцию для оценки выражения следующим образом:
E[n_Integer] := n
E[f_ + g_] = E[f] + E[g]
Для меня это гораздо более элегантно, чем любое из решений, написанных на таких языках, как OCaml, Haskell и Scala, но, конечно, это небезопасно.