LINUX.ORG.RU

[scala][generics] Ограниченно обобщенная функция

 ,


0

2

Хочу сделать обобщенную функцию, формирующую ленивый список чисел Фибоначчи произвольного типа T, поддерживающего метод +. Пытаюсь так:

object Test {

  def makeFib[T <: Any { def + (that:T):T } ](current: T, pred: T): Stream[T] = {
    Stream.cons[T]( current, makeFib[T](current + pred , current) )
  }

  def main(args: Array[String]) {
    print (makeFib[Long](1, 0).take(100).last)
  }

}

Компилятор ругается:

[error] /home/oleg/IdeaProjects/learning-scala/src/main/scala/org/ovk/learningscala/Test.scala:15: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
[error]   def makeFib[T <: Any { def + (that:T):T } ](current: T, pred: T): Stream[T] = {
[error]                              ^
[error] one error found

Можно это как-нибудь обойти?

★★★

есть у меня странное подозрение, что таким макаром функцию определять нельзя.

понаследовать класс: Any_T [T] extends Any { def + (t : T) : T} --- так работает?

Rastafarra ★★★★
()

скорее всего, тут надо какой-то имплицит определить

у тебя структурный тип; когда ты вызываешь print (makeFib[Long](1, 0).take(100).last) то внутри print неизвестно смещение в таблице виртуальных функций (или как там она в яве) для оператора + для Long — смещение надо передать отдельным параметром

www_linux_org_ru ★★★★★
()

и кстати, не переполнится ли Long от 100 фибоначей?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

скорее всего, тут надо какой-то имплицит определить

Вроде такого:

object Fib {
  trait Addable[T] {
    def add(x: T, y: T): T
  }

  implicit object IntIsAddable extends Addable[Int] {
    def add(x: Int, y: Int) = x + y
  }

  implicit object StringIsAddable extends Addable[String] {
    def add(x: String, y: String) = x + y
  }

  def makeFib[T: Addable](prev: T, cur: T): Stream[T] = {
    Stream.cons(prev, makeFib(cur, implicitly[Addable[T]].add(prev, cur)))
  }

  def main(args: Array[String]) {
    println(makeFib(0, 1).take(10).toList)
    println(makeFib("0", "1").take(10).toList)
  }
}
?

внутри print неизвестно смещение в таблице виртуальных функций

А разве там не через reflection идет вызов для структурного типа?

kamre ★★★
()
Ответ на: комментарий от kamre

> А разве там не через reflection идет вызов для структурного типа?

незнаю

но думаю что нет — иначе нафига тратить место и время писать буковки при том, что никакой типобезопасности это не дает, да и тормоза

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от kamre

Получилось даже немного проще:

object Test {

  trait Addable[T] {
    def + (that: T): T
  }

  implicit def Long2Addable(x: Long) = new Addable[Long] { def + (that: Long) = x + that }

  implicit def String2Addable(x: String) = new Addable[String] { def + (that: String) = x + that }

  def makeFib[T <% Addable[T] ](current: T, pred: T): Stream[T] = {
    Stream.cons[T]( current, makeFib[T](current + pred , current) )
  }

  def main(args: Array[String]) {

    println (makeFib[Long](1, 0).take(30).last)
    println (makeFib[String]("1", "0").take(10).last)

  }

}
[info] == run ==
[info] Running org.ovk.learningscala.Test 
832040
10110101101101011010110110101101101011010110110101101011011010110110101101011011010110110
[info] == run ==

ovk48 ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.