Я думаю, что чистый подход в этом случае (даже в F #) заключается в использовании базового объектно-ориентированного программирования и определения интерфейса с необходимыми членами (например, Property
):
type IHasProperty =
abstract Property : int
Обратите внимание, что F # подразумевает, что мы объявляем интерфейс, потому что он имеет только абстрактные члены и не имеет конструктора.Затем вы можете реализовать интерфейс в ваших типах:
type FooA = {...}
interface IHasProperty with
member this.Property = ...
type FooB = {...}
interface IHasProperty with
member this.Property = ...
Стоит отметить, что любые типы F # (включая записи, различимые объединения и, конечно, классы) могут реализовывать интерфейсы.Теперь универсальная функция может просто принимать два аргумента типа IHasProperty
:
let sum (a: IHasProperty) (b: IHasProperty) = a.Property + b.Property
. В этом случае вам даже не нужны универсальные шаблоны, но есть несколько приемов, которые универсальные шаблоны могут делать и с интерфейсами -Вы можете потребовать параметр типа T
для реализации некоторого указанного интерфейса, но здесь это не нужно, потому что F # будет автоматически преобразовывать аргументы из типов, таких как FooA
, в интерфейс, когда вы пишете sum f1 f2
.
Использование интерфейсов и типов, которые являются неизменяемыми, часто очень полезно в F #.Может быть «более функциональное» решение вашей проблемы, но для этого потребуется больше контекста.