Вопрос

I am having problems defining a type constructor to do away with the horrible type-lambda approach to partial type application in Scala. Given:

trait Sys[S <: Sys[S]]

trait Expr[S <: Sys[S], +A] {
  def value: A
}

import reflect.ClassTag

trait Proc[S <: Sys[S]] {
  def attribute[A[~ <: Sys[~]]](key: String)
                               (implicit tag: ClassTag[A[S]]): Option[A[S]]
}

Let's say I have this method:

def name[S <: Sys[S]](p: Proc[S]): String = 
  p.attribute[({type A[~ <: Sys[~]] = Expr[~, String]})#A]("name")
    .fold("<unnamed>")(_.value)

I want to define it rather like this:

def name[S <: Sys[S]](p: Proc[S]): String = 
  p.attribute[XXX[String]]("name").fold("<unnamed>")(_.value)

The question is: How can I define the type constructor XXX[A]?

My idea was this:

type XXX[A] = ({type Ex[S <: Sys[S]] = Expr[S, A]})#Ex

But it only produces

<console>:52: error: type Ex takes type parameters
       type XXX[A] = ({type Ex[S <: Sys[S]] = Expr[S, A]})#Ex
                                                           ^
Это было полезно?

Решение

I can't seem to find a solution other than staying with a type-projection, only shorter:

trait Ex[A] { type L[S <: Sys[S]] = Expr[S, A] }

def name[S <: Sys[S]](p: Proc[S]): String = 
  p.attribute[Ex[String]#L]("name").fold("<unnamed>")(_.value)

This is still not what I want. Can I get rid of the type-projection altogether?


A second idea is to provide an extension method:

implicit class RichProc[S <: Sys[S]](val `this`: Proc[S]) extends AnyVal {
  def attrExpr[A](key: String)
                 (implicit tag: ClassTag[Expr[S, A]]): Option[Expr[S, A]] =
    `this`.attribute[({type Ex[~ <: Sys[~]] = Expr[~, A]})#Ex](key)
}

def name[S <: Sys[S]](p: Proc[S]): String = 
  p.attrExpr[String]("name").fold("<unnamed>")(_.value)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top