#scala #dependent-type #path-dependent-type #type-projection
#scala #зависимый тип #тип, зависящий от пути #тип-проекция
Вопрос:
В моем приложении у меня есть замкнутый набор операций, которые возвращают соответствующий набор ответов, как показано ниже.
sealed trait OperationCompletionResponse {
val state: Int
}
case class ExecutionStartedResponse(state: Int) extends OperationCompletionResponse
case class UpdateRecordedResponse(state: Int) extends OperationCompletionResponse
case class ExecutionTerminatedResponse(state: Int) extends OperationCompletionResponse
sealed trait Operation {
type R
def createResponse(state: Int): R
}
case class StartExecutionOperation() extends Operation {
type R = ExecutionStartedResponse
override def createResponse(state: Int): ExecutionStartedResponse = ExecutionStartedResponse(state)
}
case class RecordUpdateOperation() extends Operation {
type R = UpdateRecordedResponse
override def createResponse(state: Int): UpdateRecordedResponse = UpdateRecordedResponse(state)
}
case class TerminateExecutionOperation() extends Operation {
type R = ExecutionTerminatedResponse
override def createResponse(state: Int): ExecutionTerminatedResponse = ExecutionTerminatedResponse(state)
}
Насколько я понимаю элементы типа и проекцию типа, я могу сделать следующее. Они являются совершенно допустимыми операторами в соответствии с компилятором scala
val esr:StartExecutionOperation#R = ExecutionStartedResponse(1)
val teo:TerminateExecutionOperation#R = ExecutionTerminatedResponse(-1)
val ruo:RecordUpdateOperation#R = UpdateRecordedResponse(0)
Однако теперь я хотел бы использовать их в функции; что часто бывает более полезным. Теперь, как бы мне указать тип вывода в качестве зависимого типа?
def updateState[O <: Operation](operation: O) = operation match {
case StartExecutionOperation() => ExecutionStartedResponse(1)
case TerminateExecutionOperation() => ExecutionTerminatedResponse(-1)
case RecordUpdateOperation() => UpdateRecordedResponse(0)
}
Более конкретно, я не хочу, чтобы типом возвращаемой функции в моем случае была OperationCompletionResponse, а что-то вроде Operation#R или operation.R
Как я могу этого добиться?
Ответ №1:
Тип, зависящий от пути, updateState
будет напрямую связан с типом operation
. Вы не хотите совпадать operation
в теле, потому что это никогда не даст вам тип, который R
вы ищете.
Вы определили ровно одну операцию, которая дает вам это R
и вот это createResponse
. Поскольку createResponse
ожидается целочисленный аргумент, вы должны каким-то образом ввести его updateState
. Похоже, у вас есть некоторое состояние по умолчанию для каждой из операций, так что вы могли бы определить это def defaultState: Int
Operation
, а затем иметь
def updateState(op: Operation): op.R = op.createResponse(op.defaultState)`
Если это не отвечает на ваш вопрос, пожалуйста, отредактируйте его, чтобы уточнить, чего именно вы пытаетесь достичь с помощью этого состояния.
Комментарии:
1. У меня нет состояния по умолчанию. Целочисленные значения там приведены для демонстрационных целей. Тем не менее, наиболее важным моментом здесь является то, что не следует использовать соответствие шаблону, иначе зависимый тип был бы потерян, поэтому я буду рад принять ваш ответ.