Как упоминает Брайан, существует два способа сопоставления с образцом: 1. Дискриминационные объединения и 2. Активный образец на существующем типе.
Давайте начнем с этого примера Scala:
abstract class Term
case class Var(name: String) extends Term
case class Fun(arg: String, body: Term) extends Term
case class App(f: Term, v: Term) extends Term
Этот дизайн ОО может быть переведен в различимые союзы (DU) в F #:
type Term =
Var of string
| Fun of string * Term
| App of Term * Term
Основываясь на этом DUВы можете сопоставить значение Term
, чтобы найти, какой это подтип:
let eval (t: Term) =
match t with
| Var (name) -> ...
| Fun (para, body) -> ...
| App (t1, t2) -> ...
Обратите внимание, что для этого типа Term
могут быть определены методы и свойства:
type Term =
Var of string
| Fun of string * Term
| App of Term * Term
with
member x.Type() =
match x with
| Var _ -> 0
| Fun _ -> 1
| App _ -> 2
Теперь вот различия:
вы не можете определять методы для его подтипов: Var
, Fun
и App
.
методы, которые вы можете определить в Term
, являются неизменяемыми.
невозможно расширить DU после его определения.Подумайте, теперь вам нужно добавить подтип For
к Term
.Затем вы должны изменить много кода, где Term
соответствует шаблону.
в то время как в oo design, это меньше проблем.потому что новый подтип может нести свои собственные реализации.
В F # сначала следует учитывать DU, если вы хотите построить сжатое сопоставление типов по подтипам.Но это также имеет очевидные ограничения.Я думаю, что сопоставление с образцом деятельности больше соответствует классу дел в Scala (я только немного прочитал Scala):
// define the classes for different term types
[<AbstractClass>]
type Term() =
abstract Value: int with get
type Var(name:string) =
inherit Term()
override x.Value =
0
member x.Name with get() = name
type Fun(name:string, body:Term) =
inherit Term()
override x.Value =
0
member x.Name with get() = name
member x.Body with get() = body
type App(t1:Term, t2:Term) =
inherit Term()
override x.Value =
0
member x.Term1 with get() = t1
member x.Term2 with get() = t2
// the pattern function
let (|TVar|TFun|TApp|) (x:Term) =
match x with
| :? Var ->
let y = x :?> Var
TVar(y.Name)
| :? Fun ->
let y = x :?> Fun
TFun(y.Name, y.Body)
| :? App ->
let y = x :?> App
TApp(y.Term1, y.Term2)
и функция eval
с использованием активного образца:
let eval2 (t:Term) =
match t with
| TVar (name) -> 0
| TFun (name, body) -> 0
| TApp (t1, t2) -> 0
Activity patten сочетает в себе хорошие вещи с обеих сторон: функциональное программирование и объектно-ориентированное.
исх. здесь и здесь для моделей активности.
Вы можете также обратиться к оригинальной работе с активным рисунком Дона Сайма.