Skip to content

Instantly share code, notes, and snippets.

@tel
Created March 14, 2016 02:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tel/2992dcbbff7af053bc55 to your computer and use it in GitHub Desktop.
Save tel/2992dcbbff7af053bc55 to your computer and use it in GitHub Desktop.
Beautiful "Graphs" signature example from Martin Odersky's "Scala: The Simple Parts"
/**
* Partially (!) specializes Graphs signature.
*
* Note that Node and Edge are still abstract! We add new
* functionality by concretely specifying Graph, but the DSL
* still works in its limited initial form since newGraph abstracted
* over Graph construction
*
*/
trait AbstractModel extends Graphs {
class Graph(val nodes: Set[Node], val edges: Set[Edge]) extends GraphSig {
def outgoing(n: Node) = edges filter (pred(_) == n)
def incoming(n: Node) = edges filter (succ(_) == n)
lazy val sources = nodes filter (incoming(_).isEmpty)
}
def newGraph(nodes: Set[Node], edges: Set[Edge]) = new Graph(nodes, edges)
}
/**
* Here we make a totally orthogonal specialization
*/
trait ConcreteModel extends Graphs {
type Node = Person
type Edge = (Person, Person)
def succ(e: Edge) = e._1
def pred(e: Edge) = e._2
}
/**
* Signature defines an entire graph manipulation library/DSL!
*/
trait Graphs {
type Node
type Edge
// Ambient combinators (not very OO!)
def pred(e: Edge): Node
def succ(e: Edge): Node
// Rich domain object inherits from its own signature (not very ML!)
type Graph <: GraphSig
def newGraph(nodes: Set[Node], edges: Set[Edge]): Graph
trait GraphSig {
def nodes: Set[Node]
def edges: Set[Edge]
def outgoing(n: Node): Set[Edge]
def incoming(n: Node): Set[Edge]
def sources: Set[Node]
}
}
/**
* Finally, here's a totally concrete implementation "for free"
*/
class MyGraph extends ConcreteModel with AbstractModel
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment