Another approach is type classes and path-dependent types
trait RDF[Rdf <: RDF[Rdf]](using val g: GraphTyp[Rdf], val t: TripleTyp[Rdf], val n: NodeTyp[Rdf]) {
type Graph = g.Out
type Triple = t.Out
type Node = n.Out
}
trait GraphTyp[Rdf <: RDF[Rdf]] {
type Out
}
object GraphTyp {
given as GraphTyp[Rdf4j] {
type Out = Model
}
}
trait TripleTyp[Rdf <: RDF[Rdf]] {
type Out
}
object TripleTyp {
given as TripleTyp[Rdf4j] {
type Out = Statement
}
}
trait NodeTyp[Rdf <: RDF[Rdf]] {
type Out
}
object NodeTyp {
given as NodeTyp[Rdf4j] {
type Out = Value
}
}
trait Rdf4j extends RDF[Rdf4j]
trait PointedGraph[Rdf <: RDF[Rdf]] {
def pointer(using n: NodeTyp[Rdf]): n.Out
def graph(using g: GraphTyp[Rdf]): g.Out
}
In trait RDF
I had to replace type member This
with type parameter (Rdf
) because I needed it in implicit parameters g, t, n
of the trait.