Type lambdas

As a next step, let's imagine that we have a generic Filler that is capable of filling different containers with different kinds of contents, as shown in the following code snippet:

sealed trait Contents
case class Water(purity: Int) extends Contents
case class Whiskey(label: String) extends Contents

sealed trait Container[C] { def contents: C }
case class Glass[C](contents: C) extends Container[C]
case class Jar[C](contents: C) extends Container[C]

sealed trait Filler[C <: Contents, CC <: Container[C]] {
def fill(c: C): CC
}

What could we do if we had a requirement to provide a method that should only accept one type of container or content? We would need to fix the second type parameter in a similar fashion to how we would partially apply a function if given one of the arguments. A type alias can be used to do this on the type level:

type WaterFiller[CC <: Container[Water]] = Filler[Water, CC]

def fillWithWater[CC <: Container[Water]](container: CC)(filler: WaterFiller[CC]) = ???

But it feels a bit verbose to define a type alias just to be used once in the definition of the function parameter. Type lambda is a syntax that allows us to do such partial type application in-place:

def fillWithWater[CC <: Container[Water], F: ({ type T[C] = Filler[Water, C] })#T[CC]](container: CC)(filler: F) = ???

The type lambda can also be used to define a parameter type directly:

def fillWithWater[CC <: Container[Water]](container: CC)(filler: ({ type T[C] = Filler[Water, C] })#T) = ???

The internal definition of T[C] is analogous to the type alias we defined previously. The added part is the type projection, ()#T[C], that allows us to reference the type we've just defined.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.151.44