Scala的“等同类”在F# [英] Equivalent of Scala "case class" in F#

查看:99
本文介绍了Scala的“等同类”在F#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



个案类在您想要创建自定义类的时候非常有用。

我在寻找Scala中可用的案例类F#中的等价物。方法和字段,仍然可以使用它们进行模式匹配,如本文章所述


$ b

解决方案

正如Brian所提到的,模式匹配有两种方式:1.在现有类型上区分联合和2.活动模式。



我们从这个Scala例子开始:

<$ c
case class Var(name:String)extends Term
case class Fun(arg:String,body:Term)extends Term
case class App(f:Term, v:Term)扩展Term

这个OO设计可以转换为F#中的区分工会(DU)


$ b

  type Term = 
字符串变量
|字符串的乐趣*期限
|应用期限*期限

基于此DU,您可以匹配期限 value来查找它的子类型:

  let eval(t :Term)= 

|匹配t Var(名称) - > ...
|乐趣(para,body) - > ...
| App(t1,t2) - > ...

请注意,您可以在此 Term上定义方法和属性 type:


$ b

  type Term = 
字符串的变量
|字符串的乐趣*期限
|应用期限*期限

成员x.Type()=
匹配x与
| Var _ - > 0
|有趣_ - > 1
| App _ - > 2

现在来看差异:


  1. 您无法在其子类型上定义方法: Var Fun 应用

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


  3. 一旦定义DU,就不可能扩展DU。想想你现在需要添加 For 子类型到 Term 。然后,您必须更改 Term 模式匹配的大量代码。


  4. 在oo设计中,这不是什么问题。因为新的子类型可以携带自己的实现。


在F#中,当您想要在子类型上构建简洁类型匹配时,应首先考虑DU。但它也有明显的限制。我认为活动模式匹配更像Scala中的case类(我只读了一点Scala):

 定义不同术语类型的类
[< AbstractClass>]
type Term()=
抽象值:int with get

类型Var(name:string)=
inherit Term()
覆盖x.Value =
0
成员x.Name with get()= name

类型Fun(名称:string,body:Term)=
inherit Term()
覆盖x.Value =
0
成员x.Name with get()= name
成员x.Body with get()= body


type App(t1:Term,t2:Term)=
inherit Term()
重写x.Value =
0
成员x.Term1 with get()= t1
成员x.Term2 with get()= t2

//模式函数
let(| TVar | TFun | TApp |)(x:Term)=
match x with
| :? Var - >
let y = x:?> Var
TVar(y.Name)
| :?趣味 - >
let y = x:?> Fun
TFun(y.Name,y.Body)
| :?应用程序 - >
let y = x:?> App
TApp(y.Term1,y.Term2)

eval 使用活动模式的函数:
$ b

  let eval2(t :Term)= 

|匹配t TVar(名称) - > 0
| TFun(name,body) - > 0
| TApp(t1,t2) - > 0

活动模式结合了双方的优点:函数式编程和面向对象。

ref。 此处在这里查看活动模式。

您可以进一步参考原件Don Syme撰写的关于活动模式的论文

I am looking for the equivalent in F# of "case classes" that are available in Scala.

Cases classes are very useful when you want to create custom classes with methods and fields and still be able to use them with pattern matching, as described in this article of the Scala website.

Does anyone know if the same exists in F#?

解决方案

As Brian mentions, there are two ways for pattern matching: 1. Discriminated unions and 2. active pattern on an existing type.

Let's start from this Scala example:

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

This OO design could be translated to discriminated unions (DU) in F#:

type Term = 
    Var of string 
    | Fun of string * Term 
    | App of Term * Term

Base on this DU, you can matching a Term value to find what subtype it is:

let eval (t: Term) = 
    match t with
    | Var (name) -> ...
    | Fun (para, body) -> ...
    | App (t1, t2) -> ...

Notice that you can have methods and properties defined on this Term type:

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

Now here comes the differences:

  1. you cannot define methods on its subtypes: Var, Fun, and App.

  2. the methods you can define on Term are immutable.

  3. it is not possible to extend a DU once it is defined. Think about you now need to add a For subtype to Term. Then you have to change a lot of code where a Term is pattern matched.

  4. while in oo design, it is less a problem. because the new subtype could carry its own implementations.

In F#, DU should be first considered when you want to build succinct type matching over subtypes. But it also has obvious restrictions. I think activity pattern matching is more equal to the case class in Scala (I only read a little 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)

and the eval function using active pattern:

let eval2 (t:Term) = 
    match t with
    | TVar (name) -> 0
    | TFun (name, body) -> 0
    | TApp (t1, t2) -> 0

Activity patten combines the good things on both sides: functional programming and object oriented.

ref. here and here for activity patterns.

You can further refer to the original paper on active pattern by Don Syme.

这篇关于Scala的“等同类”在F#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆