F#和Scala中ADT之间的主要区别是什么?有没有F#的ADT可以做但Scala的ADT不能(反之亦然)?
答案 0 :(得分:14)
从概念上讲,我认为两种语言都提供相同的功能 - 在F#中,您可以使用区分联合声明ADT,而在Scala中,您可以使用案例类。 Scala中使用类的声明可能会比F#版本稍长一些(正如Yin Zhu所指出的那样),但是你可以在两种语言中使用类似优点的模式匹配。
以下是简化术语的示例(from this article):
def simplify(term: Term) = term match {
case Mul(Num(0), x) => Num(0)
case Mul(Num(1), x) => x
case _ => term
}
使用match
的F#中的相同代码看起来非常相似:
let simplify term =
match term with
| Mul(Num(0), x) -> Num(0)
| Mul(Num(1), x) -> x
| _ -> term
差异我认为在更高级(相关)功能方面存在一些差异。
在Scala中,每个案例也是一个类型,因此您可以定义一个以Num
或Mul
作为参数的方法。在F#中,这是不可能的,因为Num
和Mul
只是Term
类型的构造函数。我想这可能有时很有用,但大多数时候,无论如何,你都会使用Term
类型的值。
与前一点相关 - 在Scala中,您还可以为单个案例定义方法。例如,您可以在Num
类中定义方法。在F#中,所有成员都必须是Term
类型的成员。
在F#中,您可以使用活动模式来隐藏类型的内部表示(例如,从模块导出时)。这对于库设计非常有用。例如,您可以定义活动模式:
val (|Mul|_|) // return Some(..) if Term represents multiplication
val (|Num|_|) // return Some(..) if Term represents number
内部表示可以随着时间的推移而不影响库接口,因此您可以实现如下界面:
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
答案 1 :(得分:-2)
首先,没有语言可以,其他不能。
风格有所不同。
我读了一点Scala,但不能写。我认为二元搜索树是比较ADT风格的一个很好的例子。
这是来自http://aperiodic.net/phil/scala/s-99/的代码:
package binarytree {
sealed abstract class Tree[+T]
case class Node[+T](value: T, left: Tree[T], right: Tree[T]) extends Tree[T] {
override def toString = "T(" + value.toString + " " + left.toString + " " + right.toString + ")"
}
case object End extends Tree[Nothing] {
override def toString = "."
}
object Node {
def apply[T](value: T): Node[T] = Node(value, End, End)
}
}
我们可以看到风格很大。
以下是我的Treap代码(平衡二叉搜索树)的主要部分:
module Treap =
type node<'T> = {left: treap<'T>; right: treap<'T>; value: 'T; priority:int}
and treap<'T> = Empty | Node of node<'T>
let rec lookup (k:'a) (t:'a treap) =
match t with
| Empty -> None
| Node(n) ->
if k = n.value then Some(k)
elif k < n.value then lookup k (n.left)
else lookup k (n.right)
let add (k:'a) (p:int) (tree:'a treap) =
let rotate xv xp yv yp a b c =
if xp < yp then
{value=xv; priority=xp; left=a; right=Node({value=yv;priority=yp;left=b;right=c})}
else
{value=yv; priority=yp; right=c; left=Node({value=xv; priority=xp; left=a; right=b})}
let rec addNode (k:'a) (p:int) (tree:'a treap) =
match tree with
| Empty -> {value=k; priority=p; left=Empty; right=Empty}, false
| Node(n) ->
if k=n.value then
n, true
elif k<n.value then
let {value=xv; priority=xp; left=a; right=b}, dup = addNode k p (n.left)
(rotate xv xp (n.value) (n.priority) a b (n.right)), dup
else
let {value=yv; priority=yp; left=b; right=c}, dup = addNode k p (n.right)
(rotate (n.value) (n.priority) yv yp (n.left) b c), dup
let n, dup = addNode k p tree
Node(n)
我认为Scala也可以用这种风格写作。但是,Scala更为OO。