Reputation: 2747
In Haskell I can define a generic type for a tree as:
type Tree t = Leaf t | Node (Tree t) (Tree t)
If I want to define a function for a specific parameterization of Tree, I can simply do:
-- 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
We can define a similar tree type in Scala with:
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]
But how can I define a method for Tree that only applies to certain types? Do I need to use inheritance or there's a way to say:
abstract class Tree[T]() {
// Method only for Tree[String]:
def foo[String] = ...
}
Upvotes: 1
Views: 190
Reputation: 16085
In Haskell types don't have instance methods like Scala does.
foo
in your example should be defined (preferably) in Tree
's companion object.
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 a sealed
class or trait is more appropriate here. (Scala's sealed abstract vs abstract class)
PS II: I am just typing Gregor Raýman's comment as an answer.
Upvotes: 2
Reputation: 170713
The obvious way (and equivalent to Haskell) is to define a method which takes Tree[String]
as an argument, as in muhuk's answer. If you want it to look like a method on Tree[String]
, you can use implicit class:
implicit class Foo(val tree: Tree[String]) {
def foo = ...
}
val tree: Tree[String] = ...
tree.foo // Foo needs to be in scope here
I recommend avoiding Akos Krivachy's answer in most circumstances.
Upvotes: 0
Reputation: 4966
This may not be the answer you are looking for, as I haven't done much Haskell, but it's a possibility: You can define a trait
that can only be mixed into specific instances of a tree:
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
}
You would use this like this:
val sNode = new Node(Leaf("a"), Leaf("b")) with StringFooFunctionality
sNode.foo
// Yay
The downside is that it explicitly needs to be mixed in on object creation.
Other possibility is to create a new trait called StringTree
:
trait StringTree extends Tree[String] {
def foo = ...
}
But you would have to define the other String
datatypes:
case class StringLeaf(t: String) extends StringTree
case class StringNode(left: StringTree, right: StringTree) extends StringTree
And when you encounter a Tree[T]
you can pattern match on it to see if it's StringTree
.
Upvotes: 1