What I want to do is save operator with number in list and evaluate it after pushing it to list
need 2 types of operator Add and Multiply
Plus(x) (x is number)
Multiply(x) (x is number)
lis = [ Plus(3), Multiply(3), Plus(4), Multiply(2) ]
When Plus Start
lis.fold(0) { total, operator -> blar..blar }
-> (((0 3) * 3) 4) * 2
When Multiply Start
lis.fold(1) { total, operator -> blar..blar }
how to declare abstract operator
I think Plus and Multiply Operator has one infix function something like below
infix fun <T>evaluate(value: T): T = this value
or
infix fun <T>evaluate(value: T): T = this*value
CodePudding user response:
In order to allow the distinction whether to use a 0 or a 1 depending on the first element, you could define your operation with an identity
element:
open class Operation(
val op: (Double) -> Double,
val identity: Double,
)
class Plus(operand: Double) : Operation({ it operand }, 0.0)
class Multiply(operand: Double) : Operation({ it * operand }, 1.0)
Then, the application of all elements in a list can be defined as:
fun List<Operation>.apply(): Double = if (isEmpty()) 1.0 else
fold(first().identity) { total, operation -> operation.op(total) }
The application of all elements as in your example can then be invoked using apply
:
val lis = listOf(Plus(3.0), Multiply(3.0), Plus(4.0), Multiply(2.0))
lis.apply()
If you do not like that an operator is defined and applied via its property op
(e.g. the application of Plus(3.0)
to a value 5.0
is done by Plus(3.0).op(5.0)
), we can alternatively define Operation
and the concrete subclasses in the following way:
abstract class Operation(val identity: Double) {
abstract operator fun invoke(x: Double): Double
}
class Plus(private val operand: Double) : Operation(0.0) {
override fun invoke(x: Double): Double = x operand
}
class Multiply(private val operand: Double) : Operation(1.0) {
override fun invoke(x: Double): Double = x * operand
}
Then, the apply
function would also change:
fun List<Operation>.apply(): Double = if (isEmpty()) 1.0 else
fold(first().identity) { total, operation -> operation(total) }
which might look a bit more intuitive.
The invoke
operator allows us to apply the Operation
like a function to a value, e.g. you can also write Plus(3.0)(5.0)
to apply _ 3.0
to the value 5.0
.