Thanks to this post I'm getting my head around dependent method types. I have a structure similar to the following

trait Environment{
    type Population <: PopulationBase
    protected trait PopulationBase

    def evolveUs(population: Population): Population
}

object FactoredOut{
    def evolvePopulation(env: Environment)(prevPopulation: env.Population): env.Population = {
        env.evolveUs(prevPopulation)
    }
}

I now want to start using actors to spread the work in the FactoredOut part across a cluster. To do this I need a way to pass immutable messages which carry the Environment.

Obviously the following doesn't work, but demonstrates what I'm trying to do

object Messages{
    case class EvolvePopulation(env: Environment)(prevPopulation: env.Population)
}

What is the correct way to pass the population and it's enclosing environment around?

(Would have added the dependent-method-types tag, but I don't have enough points to add a 'new' tag)

link|improve this question

feedback

1 Answer

up vote 1 down vote accepted

Your intuition that you need to pack up both the value of the dependent type (env.Population) and the value that the type depends on (env) as a single object is exactly right.

Given the definitions you've already posted, probably the simplest approach would be something like this,

// Type representing the packaging up of an environment and a population
// from that environment
abstract class EvolvePopulation {
  type E <: Environment
  val env : E
  val prevPopulation : env.Population
}

object EvolvePopulation {
  def apply(env0 : Environment)(prevPopulation0 : env0.Population) =
    new EvolvePopulation {
      type E = env0.type
      val env : E = env0 // type annotation required to prevent widening from
                         // the singleton type
      val prevPopulation = prevPopulation0
    }
}

Now if we define a concrete environment type,

class ConcreteEnvironment extends Environment {
  class Population extends PopulationBase
  def evolveUs(population: Population): Population = population
}

we can use it directly as before,

val e1 = new ConcreteEnvironment

val p1 = new e1.Population
val p2 = e1.evolveUs(p1)
val p3 = e1.evolveUs(p2)

and we can also package up an environment and population for distribution,

def distrib(ep : EvolvePopulation) {
  import ep._
  val p4 = env.evolveUs(prevPopulation)
  val p5 = env.evolveUs(p4)
  val p6 = env.evolveUs(p5)
}

val ep1 = EvolvePopulation(e1)(p3)

distrib(ep1)
link|improve this answer
Fantastic, as ever. Wouldn't have been following this at all if it hadn't been for the type system deep dive on your course. – Pengin 21 mins ago
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.