iOS
Swift

【Swift】使いこなせば便利?〜再帰的列挙型〜

これは?

みなさんは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)

上記のプログラムは以下のような定義となります。

  • ArithmeticExpressionnumber として five を初期化
  • ArithmeticExpressionnumber として four を初期化
  • ArithmeticExpressionnumber として two を初期化
  • ArithmeticExpressionaddition として fivefour を被演算子に指定して sum を初期化
  • ArithmeticExpressionmultiplication として sumtwo を被演算子に指定して 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 関数は以下のような定義となります。

  1. ArithmeticExpressionを引数として受け取る
  2. switch文でケースを分岐する
    • .numberならば: その associated value であるInt型を返す
    • .additionならば: 2つの被演算子をそれぞれ evaluate 関数に引数として渡してその結果を加算する
    • .multiplicationならば: 2つの被演算子をそれぞれ evaluate 関数に引数として渡してその結果を乗算する

この関数 evaluateproduct を引数として渡すと、その演算結果である 18 が返ってきます。

このように、再帰的列挙型は再帰関数とともに扱うことで非常に直感的なコーディングが可能になります。

参考

Apple Inc. “The Swift Programming Language" -Enumerations