【问题标题】:Equivalent of Scala "case class" in F#等效于 F# 中的 Scala“案例类”
【发布时间】:2011-09-15 08:10:09
【问题描述】:

我正在 F# 中寻找 Scala 中可用的“案例类”的等价物。

当您想要创建具有方法和字段的自定义类并且仍然能够将它们与模式匹配一​​起使用时,案例类非常有用,如 Scala 网站的 article 中所述。

有谁知道 F# 中是否存在相同的情况?

【问题讨论】:

    标签: scala f# functional-programming


    【解决方案1】:

    歧视性工会?您可以向它们添加成员方法。或者,您可以在现有类上使用活动模式。

    【讨论】:

    • 我试图在 MSDN 上查看如何将成员方法添加到被定义的联合,但我找不到它。你能举个例子吗?
    • @JSmaga,请参阅我关于向 DU 类型添加方法的答案。
    【解决方案2】:

    正如 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
    

    现在有区别了:

    1. 您不能为其子类型定义方法:VarFunApp

    2. 您可以在Term 上定义的方法是不可变的。

    3. 一旦定义了 DU,就无法对其进行扩展。想想你现在需要将For 子类型添加到Term。然后你必须更改很多代码,其中 Term 是模式匹配的。

    4. 在 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 结合了双方的优点:函数式编程和面向对象。

    参考。 herehere 用于活动模式。

    您可以进一步参考 Don Syme 的 the original paper on active pattern

    【讨论】:

    • 优秀的答案!谢谢你。我仍然认为在 Scala 中更容易,我想知道 F# 是否会在以后包含此功能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    • 2013-02-18
    • 1970-01-01
    • 2011-08-17
    • 1970-01-01
    相关资源
    最近更新 更多