Reputation: 526
I'm learning recursive enums in Swift 5.1 with Swift documentation.
Here is a code.
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
print(ArithmeticExpression.evaluate(product))
I think something is going wrong in the last line of code.
What does that mean?
Upvotes: 4
Views: 138
Reputation: 63369
evaluate(_:)
is an instance function of ArithmeticExpression
, i.e. you have to call it on an instance of ArithmeticExpression
(with that instance being what self
refers to). The type of evaluate(_:)
is (ArithmeticExpression) -> Int
.
Swift lets you call instance functions on types. What you get back is an unbound instance function. That is to say, a function with no value bound as its self
value yet. That's what you're doing when you run ArithmeticExpression.evaluate
on its own. The unbound instance function that you get back has the type:
(ArithmeticExpression) -> (ArithmetricExpression) -> Int
// ^--- the "self" ^--- the "expression" param ^--- the final return value.
By calling it and providing product
as an argument (ArithmeticExpression.evaluate(product)
), what you get back is a function of type (ArithmeticExpression) -> Int
. This function is a bound instance function, i.e. self
is now bound (it now has the value of product
), but it's awaiting to be called yet again, with another ArithmeticExpression
as an argument.
There's two ways to solve this to achieve what you want:
Either make this a static function. A static function isn't called on an instance, it's called directly on the type, as you tried to do:
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
// Make it static here
static func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
print(ArithmeticExpression.evaluate(product))
Keep evaluate
as an instance function, but call it directly on the instance your want to evaluate, rather than on the type. Since self
would be the expression you're interested in, you no longer need the expression
parameter:
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
func evaluate() -> Int {
switch self {
case let .number(value):
return value
case let .addition(left, right):
return left.evaluate() + right.evaluate()
case let .multiplication(left, right):
return left.evaluate() * right.evaluate()
}
}
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
print(product.evaluate())
I would say this is probably the more "idiomatic" version.
Upvotes: 2