Я новичок в Scala, и я пытаюсь использовать ограничения типов, чтобы избежать дублирования кода в следующем коде (очищенном от ненужного):
trait StandardStep1[-I1] {
def next_step(i:I1):StandardStep2
}
trait StandardStep2
trait UniqueStep1[-I1] extends StandardStep1[I1] {
def next_step(i:I1):UniqueStep2
}
trait UniqueStep2 extends StandardStep2
class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends StandardStep1[(IL,IR)] {
def next_step(i:(IL,IR)) = {
val (i_left, i_right) = i
val new_left = left.next_step(i_left)
val new_right = right.next_step(i_right)
new DoubleStandardStep2(new_left, new_right)
}
}
class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2
class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends UniqueStep1[(IL,IR)] {
def next_step(i:(IL,IR)) = {
val (i_left, i_right) = i
val new_left = left.next_step(i_left)
val new_right = right.next_step(i_right)
new DoubleUniqueStep2(new_left, new_right)
}
}
class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2
Объяснение:
StandardStep1
представляет собой шаг в некоторой конечной машине и имеет операцию next_step
, которая дает StandardStep2
для данного входа.
UniqueStep1
— это особый тип StandardStep1
, который дает UniqueStep2
при вызове next_step
— и, очевидно, UniqueStep2
для этого должен наследоваться от StandardStep2
.
Теперь мне пришлось написать обертки DoubleStep: DoubleStandardStep1
обертывает также StandardStep1
s и возвращает DoubleStandardStep2
при вызове его next_step
. DoubleUniqueStep1
делает то же самое, но возвращает DoubleUniqueStep2
.
Реализация *DoubleStep*s' next_step
имеет очевидное дублирование кода: они оба разбивают входные данные на i_left
и i_right
и одинаково вызывают свои обернутые шаги next_step
.
Мне было интересно, как устранить это дублирование кода, создав общий абстрактный DoubleStep1, который будет выполнять эту часть кода:
object DoubleStepHelper {
def next_step_args[IL,IR,SL <: StandardStep1[IL],SR <: StandardStep1[IR]](left:SL,right:SR)(i:(IL,IR)) = {
val (i_left, i_right) = i
val new_left = left.next_step(i_left)
val new_right = right.next_step(i_right)
(new_left, new_right)
}
}
class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends StandardStep1[(IL,IR)] {
def next_step(i:(IL,IR)) = {
((l,r) => new DoubleStandardStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i))
}
}
class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2
class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends UniqueStep1[(IL,IR)] {
def next_step(i:(IL,IR)) = {
((l,r) => new DoubleUniqueStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i))
}
}
class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2
Попытка скомпилировать этот код (scala 2.9.2) завершается ошибкой с сообщением:
type mismatch; found : (this.StandardStep2, this.StandardStep2) required: (this.UniqueStep2, this.UniqueStep2) ((l,r) => new DoubleUniqueStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i)) ^
Я предполагаю, что это происходит потому, что предполагается, что DoubleStepHelper.next_step_args
возвращает значение (StandardStep2, StandardStep2)
, что плохо, когда мы хотим обернуть его DoubleUniqueStep2
.
Можете ли вы придумать способ решить эту проблему? Как сообщить компилятору, что next_step_args DoubleStepHelper
может возвращать (UniqueStep2, UniqueStep2)
, если SL
и SR
наследуются от UniqueStep1
?
Хорошей функцией может быть возможность определить тип результата next_step_args
как что-то вроде (SL.next_step, SR.next_step), что означает, что его тип возвращаемого значения создается из типов возвращаемых значений определенных функций ( следующий_шаг) в SL
и SR
.
Могут ли границы «представления» решить эту проблему каким-либо образом?
Я мог бы принудительно выполнить кастинг, используя asInstanceOf, но это выглядит некрасиво.
Спасибо