【发布时间】:2011-09-15 08:10:09
【问题描述】:
我正在 F# 中寻找 Scala 中可用的“案例类”的等价物。
当您想要创建具有方法和字段的自定义类并且仍然能够将它们与模式匹配一起使用时,案例类非常有用,如 Scala 网站的 article 中所述。
有谁知道 F# 中是否存在相同的情况?
【问题讨论】:
标签: scala f# functional-programming
我正在 F# 中寻找 Scala 中可用的“案例类”的等价物。
当您想要创建具有方法和字段的自定义类并且仍然能够将它们与模式匹配一起使用时,案例类非常有用,如 Scala 网站的 article 中所述。
有谁知道 F# 中是否存在相同的情况?
【问题讨论】:
标签: scala f# functional-programming
歧视性工会?您可以向它们添加成员方法。或者,您可以在现有类上使用活动模式。
【讨论】:
正如 Brian 所提到的,模式匹配有两种方法: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
这种 OO 设计可以转换为 F# 中的可区分联合 (DU):
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 设计中,这不是问题。因为新的子类型可以携带自己的实现。
在 F# 中,当您要在子类型上构建简洁的类型匹配时,应首先考虑 DU。但它也有明显的限制。我认为活动模式匹配更等于Scala中的case类(我只看了一点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 结合了双方的优点:函数式编程和面向对象。
您可以进一步参考 Don Syme 的 the original paper on active pattern。
【讨论】: