これは?
みなさんはSwiftの 再帰的列挙型 というものをご存知でしょうか。
本稿では、意外と知られていない 再帰的列挙型 の使い方について説明します。
再帰的列挙型とは?
再帰的列挙型とは、 associated value としてその列挙型自身を再帰的に持つ列挙型のことです。
言葉だけではわかりにくいので、実際に例を示します。
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
上記のプログラムは、単純な演算を行うための再帰的列挙型の定義です。
一つ目のケースはInt型を associated value として持ちます。
演算のために使う被演算子の定義です。
二つ目と三つ目のケースはそれぞれ加算と乗算の定義です。
そしてどちらも ArithmeticExpression 自身を associated value として持ちます。
このような場合、caseの前に indirect修飾子 を付加します。
活用例
例えば、この ArithmeticExpression を利用して、 (5 + 4) * 2 という演算を処理してみましょう。
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let two = ArithmeticExpression.number(2)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, two)
上記のプログラムは以下のような定義となります。
-
ArithmeticExpressionのnumberとしてfiveを初期化 -
ArithmeticExpressionのnumberとしてfourを初期化 -
ArithmeticExpressionのnumberとしてtwoを初期化 -
ArithmeticExpressionのadditionとしてfiveとfourを被演算子に指定してsumを初期化 -
ArithmeticExpressionのmultiplicationとしてsumとtwoを被演算子に指定してproductを初期化
さて、これで演算を行う準備が整いました。
変数 product は (5 + 4) * 2 の演算を 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)
}
}
print(evaluate(product))
// Prints "18"
上記の evaluate 関数は以下のような定義となります。
- ArithmeticExpressionを引数として受け取る
- switch文でケースを分岐する
- .numberならば: その associated value であるInt型を返す
- .additionならば: 2つの被演算子をそれぞれ
evaluate関数に引数として渡してその結果を加算する - .multiplicationならば: 2つの被演算子をそれぞれ
evaluate関数に引数として渡してその結果を乗算する
この関数 evaluate に product を引数として渡すと、その演算結果である 18 が返ってきます。
このように、再帰的列挙型は再帰関数とともに扱うことで非常に直感的なコーディングが可能になります。