在Haskell中,我可以将树的泛型类型定义为:
type Tree t = Leaf t | Node (Tree t) (Tree t)
如果我想为Tree的特定参数化定义一个函数,我可以这样做:
-- 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]
但是如何为Tree定义仅适用于某些类型的方法?我需要使用继承还是可以说:
abstract class Tree[T]() {
// Method only for Tree[String]:
def foo[String] = ...
}
答案 0 :(得分: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:IMO sealed
类或特征在这里更合适。 (Scala's sealed abstract vs abstract class)
PS II:我只是输入GregorRaýman的评论作为答案。
答案 1 :(得分:1)
这可能不是您正在寻找的答案,因为我没有做太多Haskell,但它有可能:您可以定义一个只能混合到树的特定实例中的trait
: / p>
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 :(得分:0)
显而易见的方法(相当于Haskell)是定义一个以Tree[String]
为参数的方法,就像muhuk的回答一样。如果您希望它看起来像Tree[String]
上的方法,则可以使用隐式类:
implicit class Foo(val tree: Tree[String]) {
def foo = ...
}
val tree: Tree[String] = ...
tree.foo // Foo needs to be in scope here
我建议在大多数情况下避免使用Akos Krivachy的答案。