I've just started to learn Scala and decided to implement small graph library to train.
Here is the basic version, that describes graph and nodes structure and also provides implementation of DFS to find some path from one node to other.
class Graph[A] {
var nodes = Set.empty[Node[A]]
def addNode(n: Node[A]) = nodes = nodes + n
def DFS(from: Node[A], to: Node[A]): List[Node[A]] = {
var visited = Set.empty[Node[A]]
@tailrec
def _DFS(from: Node[A], to: Node[A], path: List[Node[A]]): List[Node[A]] = {
visited = visited + from
if (from.equals(to)) path
else {
from.outgoing.find(n => !visited.contains(n)) match {
case Some(n) => _DFS(n, to, n :: path)
case None => path match {
case n :: Nil => List.empty[Node[A]]
case _ :: n :: ns => _DFS(n, to, n :: ns)
}
}
}
}
_DFS(from, to, List(from)).reverse
}
}
class Node[A](val i: A) {
var incoming = Set.empty[Node[A]]
var outgoing = Set.empty[Node[A]]
def addIncoming(n: Node[A]) = incoming = incoming + n
def addOutgoing(n: Node[A]) = outgoing = outgoing + n
}
I'm actively writing code in Java, so my primary goal is to not write Java code in Scala syntax. Hence, first and main question is: does my code looks like typical Scala code? If not, what should I change?
Next thing bothering me, is that my Node is too loosely coupled with Graph. I could invoke DFS only on instance of Graph, but apart from this, I don't really use Graph abstraction: I could just create instances of Node and link them.
That leads me to another problem. Suppose now I want to define weighted graph. For Graph itself I could define Weighted trait, but then I need to replace inner Node with NodeWithWeightedEdges, and I don't understand how.