Кажется, что код F # часто сопоставляется с типами. Конечно
match opt with
| Some val -> Something(val)
| None -> Different()
кажется обычным.
Но с точки зрения ООП это выглядит очень похоже на поток управления, основанный на проверке типа во время выполнения, которая обычно вызывает недовольство. Чтобы объяснить это, в ООП вы, вероятно, предпочтете использовать перегрузку:
type T =
abstract member Route : unit -> unit
type Foo() =
interface T with
member this.Route() = printfn "Go left"
type Bar() =
interface T with
member this.Route() = printfn "Go right"
Это, конечно, больше кода. OTOH, мне кажется, у OOP-y есть структурные преимущества:
- расширение к новой форме
T
легко; - Мне не нужно беспокоиться об обнаружении дублирования потока управления выбором маршрута; и
- Выбор маршрута является неизменным в том смысле, что, как только у меня есть
Foo
в руках, мне не нужно беспокоиться оBar.Route()
реализации
Есть ли какие-то преимущества в сопоставлении с образцом для типов, которые я не вижу? Это считается идиоматическим или это способность, которая обычно не используется?
But from an OOP perspective, that looks an awful lot like control-flow based on a runtime type check, which would typically be frowned on.
звучит слишком догматично. Иногда вы хотите отделить свои операции от своей иерархии: возможно, 1) вы не можете добавить операцию в иерархию, потому что у вас нет этой иерархии; 2) классы, которые вы хотите иметь, не соответствуют вашей иерархии; 3) вы можете добавить опцию в вашу иерархию, но не хотите, чтобы вы не хотели загромождать API своей иерархии кучей дерьма, которое не использует большинство клиентов.