2015-06-11 36 views
1

在Haskell,我可以定义一个通用型的树:Scala的泛型:专业的方法

type Tree t = Leaf t | Node (Tree t) (Tree t) 

如果我要定义一个函数树的特定参数,我可以简单地做:

-- Signature of a function that takes a tree of bool 
foo :: Tree Bool -> Int 

-- Takes a tree of numbers 
bar :: (Num n) => Tree n -> Bool 

我们可以在Scala中定义一个类似树与类型:

abstract class Tree[T]() 
case class Leaf[T](t: T) extends Tree[T] 
case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T] 

但我怎么可以定义树的方法为o只适用于某些类型?我是否需要使用继承或有一种方法说:

abstract class Tree[T]() { 
    // Method only for Tree[String]: 
    def foo[String] = ... 
} 
+0

如果Tree的类型是Int,'foo'会发生什么?你能指望什么? 'val t:Tree [Int] = ...'和't.foo()'? –

+0

我希望foo(比如Haskell的例子)只被定义为Tree [Int]。这就是为什么我想知道是否需要使用继承来从树中创建一个新类,但似乎设法派生一个新类来定义一个专门的方法。 – Suugaku

+3

您可以创建一个将树作为参数的函数,而不是将方法添加到“树”本身。该函数可以声明特定类型的树(例如'def foo(tree:Tree [String])'),或者可以使用类型模式,如果您想使其具有通用性。 –

回答

1

这可能不是你要找的答案,因为我没有做太多的Haskell,但它是一个可能性:你可以定义一个trait只能被混合成树的具体实例:

trait StringFooFunctionality { 
    this: Tree[String] => // Selftype, can only be mixed in to classes that are Tree[String] 
    def foo = "Yay" // String is the datatype of Tree here 
} 

你会使用这个像这样:

val sNode = new Node(Leaf("a"), Leaf("b")) with StringFooFunctionality 
sNode.foo 
// Yay 

的缺点是,它明确地需要在邻进行混合创建对象

另一种可能性是创建StringTree称为一个新的特点:

trait StringTree extends Tree[String] { 
    def foo = ... 
} 

但你必须定义其他String数据类型:

case class StringLeaf(t: String) extends StringTree 
case class StringNode(left: StringTree, right: StringTree) extends StringTree 

而当你遇到一个Tree[T]可以模式匹配看它是否是StringTree

2

在Haskell类型中没有像Scala那样的实例方法。

foo在你的例子中应该定义(最好)Tree的伴侣对象。

sealed abstract class Tree[T]() 
case class Leaf[T](t: T) extends Tree[T] 
case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T] 

object Tree { 
    // Method only for Tree[String]: 
    def foo(tree: Tree[String]) = ... 
} 

PS:海事组织sealed类或特质是比较合适的位置。 (Scala's sealed abstract vs abstract class

PS II:我只是输入了GregorRaýman的评论作为答案。

0

明显的方法(和Haskell相当)是定义一个方法,它需要Tree[String]作为参数,如muhuk的答案。

implicit class Foo(val tree: Tree[String]) { 
    def foo = ... 
} 

val tree: Tree[String] = ... 

tree.foo // Foo needs to be in scope here 

我建议避免在大多数情况下阿科什Krivachy的回答是:如果你想让它看起来像一个方法上Tree[String],你可以使用隐类。