Неявные преобразования по общему признаку - PullRequest
2 голосов
/ 28 января 2011

Я реализую структуру данных и хочу, чтобы пользователь мог использовать любой тип ключа в качестве ключа, если он предоставляет подходящий тип ключа для его обертывания.У меня есть черта для этого типа ключа.Идея состоит в том, чтобы иметь неявные преобразования от базового к ключевому типу и наоборот (фактически) просто использовать базовый тип.Эта черта выглядит следующим образом:

trait Key[T] extends Ordered[Key[T]] {
  def toBase : T

  // Further stuff needed for datastructure...
}
object Key {
  implicit def key2base[T](k : Key[T]) : T = k.toBase
}

Код сайта вызова может выглядеть следующим образом:

def foo[K <% Key[K]]( bar : Seq[K] ) = bar.sorted(0)

План состоит в том, что значения типа K должны быть неявно преобразованы в Key[K], чтозаказывается или порядок на Key[K] должен использоваться соответственно, поэтому все должно получиться.Конечно, не существует способа реализовать неявное base2key в самой черте.Или есть, может быть, использование неявно переданных манифестов класса?Я не мог найти никаких ссылок, учитывая это.

Можно ли как-то статически утверждать, что любой тип, расширяющий Key[T], будет иметь неявное преобразование T => Key[T]?К сожалению, у сопутствующего объекта не может быть абстрактных методов.

Предполагается, что это сработает, реально ли все предприятие или же заявленный вариант использования будет нуждаться в множественных неявных преобразованиях?(Цепочка не происходит, как я уже читал.)

Приложение: С приведенным выше определением я могу отсортировать последовательность Node(key : K, ...) (под K <% Key[K]), используя sortWith(_.key <= _.key), но не используя sortBy(_.key).Таким образом, очевидно, что преобразование из K в Key[K] происходит неявно, хотя я никогда нигде не объявлял об этом, но Ordering для Key[K] не доступно неявно.Что здесь происходит?

Ответы [ 3 ]

1 голос
/ 29 января 2011

вы спрашиваете: «Можно ли как-то статически утверждать, что любой тип, расширяющий Key[T], будет сопровождаться неявным преобразованием T => Key[T]? У объекта-компаньона не может быть абстрактных методов, к сожалению."

, но ваш пример - статическое утверждение: когда вам требуется представление от T до Key[T], вы утверждаете во время компиляции, что вы можете вызывать foo только для типов, которые можно поднять до ключей. Или я что-то неправильно понимаю?

относительно приложения: вы говорите, что удивлены тем, что «преобразование из K в Key[K] происходит неявно, даже если оно никогда нигде не объявлено мной». Дело в том, что вы объявили это: T <% Key[T] (я использую T здесь вместо K, вы, кажется, смешиваете понятие base * T * ype и * К * эй здесь?). Это идентично

def foo[T](bar : Seq[T])(implicit view: T => Key[T]) = bar.sortWith(_ <= _)(0)

таким образом, когда вы делаете sortWith(_ <= _), вы принуждаете T к Key[T] (для которого <= определяется в соответствии с чертой Ordered[Key[T]]).

на примере вашего узла, почему бы не сделать

case class Node[K](key: K)
def test[K](bar: Seq[Node[K]])(implicit ord: Ordering[K]) = bar.sortBy(_.key)(0)

надеюсь, это поможет ...

0 голосов
/ 31 января 2011

В этом ответе я сохраню лучшую на данный момент версию для справки.Использование этого ответа для более сфокусированного вопроса;устареет с 2.9 согласно этому .

Черта Key остается неизменной;Я добавляю конкретную функцию для иллюстрации:

trait Key[T] extends Ordered[Key[T]] {
  def toBase : T
  def foo(i : Int) : Key[T]
}
object Key {
  implicit def key2base[T](k : Key[T]) : T = k.toBase
  implicit def ordering[T <% Key[T]] = new Ordering[T]{
    def compare(x: T, y: T) = x compare y
  }
}

Следующее работает, как и ожидалось (если import Key._ сделано):

def min[K <% Key[K]](l : Seq[K]) : K = l.sorted.head

Предположим, у нас есть простое class Node[K](val key : K),Опять же, все работает как положено:

def min[K <% Key[K]](l : Seq[Node[K]]) : Node[K] = l.sortBy(_.key).head

В качестве другого примера, предположим, что этот код использует только интерфейс Key[T]:

def test[K <% Key[K]](bar : Seq[K]) = 
  bar.map(_.foo(3)).sorted

Обратите внимание, что это компилируется, так как map даетSeq[Key[K]] напрямую;для сортировки не требуется преобразование.Теперь, если у нас есть правильная реализация Key, скажем

class StringKey(val key : String) extends Key[String] {
  def foo(i : Int) =  StringKey(this.key + "_" + i)
  def toBase = key
  override def compare(other : Key[String]) = -1*this.key.compare(other.toBase)
}
object StringKey {
  def apply(key : String) = new StringKey(key)
  def unapply(key : String) = Some(key)
  implicit def string2key(s : String) = StringKey(s)
}

, должно работать следующее:

import StringKey.string2key
import Key.key2base
val bla : Seq[String] = test(Seq("b", "c", "a")).map(_.capitalize)
println(bla)
// expected output: Seq(C_3, B_3, A_3)

Но на самом деле, преобразование из StringKey в Stringне найдено:

error: value capitalize is not a member of this.Key[java.lang.String]

Это странно; - это преобразование из Key[String] в String, если оно объявлено с параметром универсального типа.

0 голосов
/ 28 января 2011

Вот возможное решение вашей проблемы (надеюсь, я правильно понял ваши требования):

// Key stuff

trait Keyable[T] {
  def toKey(t: T): Key[T]
}

trait Key[T] extends Ordered[Key[T]] {
  def toBase() : T
}

object Key {
  implicit def key2base[T](k : Key[T]) : T = k.toBase
  implicit def base2key[T : Keyable](k : T) : Key[T] = implicitly[Keyable[T]].toKey(k)
}

// more concrete stuff - namely A

class A(val i: Int) {
  override def toString = "A {" + i + "}"
}

object A {
  implicit val aKeyable = new Keyable[A] {
    def toKey(t: A) = new Key[A] {
      def toBase() = t
      def compare(that: Key[A]) = t.i compare that.i
    }
  }
}

// testing

def foo[K : Keyable](bar: Seq[K]) = bar.sortBy(implicitly[Keyable[K]].toKey)

val list = List(new A(5), new A(1), new A(3))

println(foo(list)) // prints: List(A {1}, A {3}, A {5})

В этом случае Key[T] - это обертка для типа T, а Keyable[T] - это тип calss, который позволяетпреобразовать тип T в Key[T].Я также показал, как может выглядеть base2key.

...