Kotlin анонимный объект, наследующий от базового класса, но сохраняющий свойства производного класса - PullRequest
0 голосов
/ 12 марта 2020

У меня проблема в том, что я не совсем уверен, как изящно вычислить:

abstract class BaseContinuousSingleObjectiveFitnessFunction {

    // Invoke should compute some function, like f(x) = x^2 + 3x + 5
    abstract fun invoke(x: List<Double>): Double

    // This is supposed to take a function that will be called on the result of invoke
    // and return an object derived from this one that has its invoke overriden to call
    // the new function on the result of the original one.
    fun modify(f: (Double) -> Double): BaseContinuousSingleObjectiveFitnessFunction {
        val originalFunction = this
        return object : BaseContinuousSingleObjectiveFitnessFunction() {
            override operator fun invoke(x: List<Double>): Double = f(originalFunction(x))
        }
    }
}

Теперь это работает, но modify не сохраняет свойства производных типов.

Так, например, скажем, я добавляю это в проект:

class XTimesA(val a: Double): BaseContinuousSingleObjectiveFitnessFunction() {
    override operator fun invoke(x: List<Double>) = x.sumByDouble { a*it }
}

Затем я хочу вызвать модифицировать его:

val f1 = XTimesA(a = 5.0)
println(f1.a) // Works

val f2 = f1.modify { it.pow(2) }
println(f2.a) // This fails because it is not recognized as deriving XTimesA

Есть ли способ не копировать- вставить modify в каждый производный класс, но при этом сохранить доступ к свойствам?

Ответы [ 2 ]

0 голосов
/ 12 марта 2020

Для этого вы можете использовать F-ограниченный полиморфизм . Что-то вроде

abstract class BaseContinuousSingleObjectiveFitnessFunction<T : BaseContinuousSingleObjectiveFitnessFunction<T>> {

    // Invoke should compute some function, like f(x) = x^2 + 3x + 5
    abstract operator fun invoke(x: List<Double>): Double

    abstract fun construct(f: (List<Double>) -> Double): T

    // This is supposed to take a function that will be called on the result of invoke
    // and return an object derived from this one that has its invoke overriden to call
    // the new function on the result of the original one.
    fun modify(f: (Double) -> Double): T = construct { list -> f(this(x)) } 
}

open class XTimesA(val a: Double): BaseContinuousSingleObjectiveFitnessFunction<XTimesA>() {
    override operator fun invoke(x: List<Double>) = x.sumByDouble { a*it }

    override fun construct(f: (List<Double>) -> Double) = object : XTimesA(a) {
        override operator fun invoke(x: List<Double>) = f(x)
    }
}

Однако в данном конкретном случае я не думаю, что это действительно имеет смысл, и ваш пример показывает, почему: f1.modify { it.pow(2) } представляет функцию x -> x.sumByDouble { 5 * it }.pow(2), которая не является x -> x.sumByDouble { a * it } для любого a!

0 голосов
/ 12 марта 2020

Если вы хотите иметь доступ к значению свойства на всех уровнях наследования, вам необходимо поднять свойство до базового класса:

abstract class BaseContinuousSingleObjectiveFitnessFunction<Value>(val value: Value) {

    abstract fun invoke(x: List<Value>): Value

    fun modify(f: (Value) -> Value): BaseContinuousSingleObjectiveFitnessFunction<Value> {
        val originalFunction = this
        return object : BaseContinuousSingleObjectiveFitnessFunction<Value>() {
            override operator fun invoke(x: List<Value>): Value = f(originalFunction(x))
        }
    }
}

Value - это тип c здесь для случая, когда Double применимо не во всех случаях. Если все значения имеют тип Double, классу не нужен этот параметр типа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...