Я ищу в F # эквивалент «классов кейсов», доступных в Scala.
Кейсы классы очень полезны, когда вы хотите создавать собственные классы с методами и полями и при этом иметь возможность использовать их с сопоставлением с образцом, как описано в этой статье веб-сайта Scala.
Кто-нибудь знает, есть ли то же самое существует в F #?
Как упоминает Брайан, есть два способа сопоставления с образцом: 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 сочетает в себе хорошее с обеих сторон: функциональное программирование и объектно-ориентированное.
исх. здесь и здесь для моделей активности.
Вы можете также обратиться к оригинальной работе по активному образцу Дона Сайма.