ADT在F#和Scala [英] ADTs in F# and 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
orMul
as an argument. In F#, this is not possible, becauseNum
andMul
are just constructors of typeTerm
. I suppose this may be sometimes useful, but most of the time, you'll work with values of typeTerm
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 theTerm
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屋!