У меня есть автоматы, у которых есть зависимые типы (я бы назвал их ассоциированными) для состояний и меток их переходов.
trait Automaton {
type State
type Label
type Transition = (State, Label, State)
}
Теперь я хочу написать класс, который принимает в качестве аргумента автомат и функцию, выполняющую некоторый подсчет переходов на этом конкретном автомате. я бы написал:
class AutomataMagic(val aut: Automaton, val h: aut.Transition => Int) {
...
}
Однако это не компилируется. Могу ли я каким-либо образом указать, что я хочу, чтобы моя функция выполняла определенные действия с типом перехода этого автомата?
Я идиот. По-видимому, вы можете просто сделать это:
class AutomataMagic[A <: Automaton](val aut: Automaton, val h: A#Transition => Int) {}
В сообщении об ошибке все сказано:
illegal dependent method type: parameter may only be referenced in a subsequent parameter section
Как сказал Луис Мигель Мехия Суарес , вам нужно переместить h
в другую группу параметров.
class AutomataMagic(val aut: Automaton)(val h: aut.Transition => Int) {}
Как ни странно, тот не работает (наверное из-за этого бага).
(Очень наивным) обходным решением будет это. Это не очень приятно, но, похоже, работает.
class AutomataMagic private(_h: Automaton#Transition => Int, val aut: Automaton) {
val h: aut.Transition => Int = _h.asInstanceOf[aut.Transition => Int]
def this(aut: Automaton)(h: aut.Transition => Int) =
this(h.asInstanceOf[Automaton#Transition => Int], aut)
}
Обновлено: Луис Мигель Мехия Суарес предложил использовать черту с сопутствующим объектом. Вот моя интерпретация этого:
trait AutomataMagic[A <: Automaton] {
val aut: A
val h: aut.Transition => Int
}
object AutomataMagic {
def apply[A <: Automaton](_aut: A)(_h: _aut.Transition => Int) = new AutomataMagic[A] {
val aut: _aut.type = _aut
val h = _h
}
}
Кстати, первый фрагмент компилируется на Scala 3.
Кроме того, вы действительно не должны использовать это:
class AutomataMagic[A <: Automaton](val aut: Automaton, val h: A#Transition => Int) {}
Мало того, что A#Transition
не имеет отношения к aut.Transition
(по крайней мере, сделайте это aut: A
), проекции типов несостоятельны и будут отброшены в Scala 3. Возможно, в данном конкретном случае для вас это не имеет значения, потому что Transition
инвариантно, но это не безопасно.
Чтобы заставить это работать, мне, вероятно, потребуется выполнить какой-то другой рефакторинг, но это к лучшему и, вероятно, улучшит качество моего кода. Спасибо!
Не делайте этого, это не означает, что вы думаете, и проекции типов устарели. Первый скомпилируется, если вы переместите функцию в другую группу параметров.