F#和Scala中的ADT

ano*_*ous 4 comparison f# scala algebraic-data-types

F#和Scala中ADT之间的主要区别是什么?有没有F#的ADT可以做但Scala的ADT不能(反之亦然)?

Tom*_*cek 14

从概念上讲,我认为两种语言都提供相同的功能 - 在F#中你可以使用有区别的联合声明ADT,而在Scala中,你可以使用case类.Scala中使用类的声明可能会比F#版本稍长一些(正如Yin Zhu所指出的那样),但是你可以在两种语言中使用类似优点的模式匹配.

以下是简化术语的示例(来自本文):

def simplify(term: Term) = term match {
  case Mul(Num(0), x) => Num(0)
  case Mul(Num(1), x) => x
  case _ => term
}
Run Code Online (Sandbox Code Playgroud)

F#using中的相同代码match看起来非常相似:

let simplify term = 
  match term with 
  | Mul(Num(0), x) -> Num(0)
  | Mul(Num(1), x) -> x
  | _ -> term
Run Code Online (Sandbox Code Playgroud)

差异我认为在更高级(相关)功能方面存在一些差异.

  • 在Scala中,每个case都是一个类型,因此您可以定义一个带NumMul作为参数的方法.在F#中,这是不可能的,因为NumMul只是类型的构造Term.我想这可能有时很有用,但大多数时候,Term无论如何你都会使用类型的值.

  • 与上一点相关 - 在Scala中,您还可以为单个案例定义方法.例如,您可以在Num类中定义方法.在F#中,所有成员都必须是该Term类型的成员.

  • 在F#中,您可以使用活动模式隐藏类型的内部表示(例如,从模块导出时).这对于库设计非常有用.例如,您可以定义活动模式:

    val (|Mul|_|) // return Some(..) if Term represents multiplication
    val (|Num|_|) // return Some(..) if Term represents number
    
    Run Code Online (Sandbox Code Playgroud)

    内部表示可以随着时间的推移而不影响库接口,因此您可以像这样实现接口:

    type Term = Binary of string * Term * Term | Num of int
    let (|Num|_|) = function Num n -> Some n | _ -> None 
    let (|Mul|_|) = function Binary("*", a, b) -> Some(a, b) | _ -> None
    
    Run Code Online (Sandbox Code Playgroud)