ADT在F#和Scala [英] ADTs in F# and Scala

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

问题描述

F#和Scala中的ADT之间的主要区别是什么?

解决方案

从概念上来说,我认为两种语言都是不可能的提供相同的权力 - 在F#中,您可以使用歧视联盟声明ADT;在Scala中,您可以使用案例类。 Scala中使用类的声明可能会比F#版本(Yin Zhu指出)长一点,但是您可以使用两种语言中类似的elegancy的模式匹配。



以下是一个示例(简单化的术语:

  def simplify(term:Term)=长期匹配{
case Mul(Num(0),x)=> Num(0)
case Mul(Num(1),x)=> x
case _ => term
}

F#中的相同代码使用 match 看起来很相似:

  let simplify term = 
匹配术语with
| Mul(Num(0),x) Num(0)
| Mul(Num(1),x) x
| _ - > term

差异高级(相关)功能。




  • 在Scala中,每个案例都是一个类型,所以你可以定义一个方法 Num Mul 作为参数。在F#中,这是不可能的,因为 Num Mul 只是类型 。我想这可能有时是有用的,但大多数时候,你将使用类型 Term 的值。


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


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

      val(| Mul | _ |)// return Some术语表示乘法
    val(| Num | _ |)// return Some(..)if Term表示数字


    b $ b

    内部表示可以随时间改变而不影响库接口,因此您可以实现如下界面:

      type Term =字符串的二进制* Term * Term | num 
    let(| Num | _ |)= function Num n - >一些n | _ - > None
    let(| Mul | _ |)= function Binary(*,a,b) - >一些(a,b)| _ - >无



What are the key differences between ADTs in F# and Scala? Is there anything that F#'s ADTs can do but Scala's ADTs cannot (and vice versa)?

解决方案

Conceptually, I think that both languages provide the same power - in F# you can declare ADTs using discriminated unions and in Scala, you can use case classes. The declaration in Scala using classes may get a little bit longer than the F# version (as pointed out by Yin Zhu), but then you can use pattern matching with similar elegancy in both of the languages.

Here is an example (from this article) of simplifying terms:

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

The same code in F# using match would look very similar:

let simplify term = 
  match term with 
  | Mul(Num(0), x) -> Num(0)
  | Mul(Num(1), x) -> x
  | _ -> term

Differences I think there are a few differences when it comes to more advanced (related) features.

  • In Scala, each case is also a type, so you can for example define a method that takes Num or Mul as an argument. In F#, this is not possible, because Num and Mul are just constructors of type Term. I suppose this may be sometimes useful, but most of the time, you'll work with values of type Term anyway.

  • Related to the previous point - in Scala, you can also define methods for individual cases. You can for example define a method in the Num class. In F#, all members have to be members of the Term type.

  • In F#, you can use active patterns to hide the internal representation of the type (e.g. when exporting it from a module). This is very useful for library design. For example, you can define active patterns:

    val (|Mul|_|) // return Some(..) if Term represents multiplication
    val (|Num|_|) // return Some(..) if Term represents number
    

    The internal representation can change over time without affecting the library interface, so you can for example implement the interface like this:

    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
    

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

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