🐡

Scala3(Dotty)でenumで自然数を定義してみる

2021/05/16に公開

Scala3がリリースされました! Bookの例にあった、enumの例で少し遊んでみました。

Scala3-Book DOMAIN MODELINGのenum

これがenumのシンプルな例です。

enum CrustSize:
  case Small, Medium, Large
  
import CrustSize.*
val currentCrustSize = Small

// enums in a `match` expression
currentCrustSize match
  case Small => println("Small crust size")
  case Medium => println("Medium crust size")
  case Large => println("Large crust size")

// enums in an `if` statement
if currentCrustSize == Small then println("Small crust size")

代数的データ型らしい使い方として、自然数をenumで定義してみた例です。

enum Nat:
  case Zero
  case Succ(pred: Nat)

これだけではつまらないので、このNatを使って足し算を定義してみましょう。左項のpred(前の値)と右項を足したもののSuccは左項 + 右項に等しいです。

def plus(left: Nat, right: Nat): Nat =
  (left, right) match
    case (Zero, r) => r
    case (l, Zero) => l
    case (Succ(pl), r) => Succ(plus(pl, r))

もっとシンプルに左項のパターンマッチだけでも定義できます。

def plus(left: Nat, right: Nat): Nat =
  left match
    case Zero => right
    case Succ(pl) => Succ(plus(pl, right))

それでは自然数をいくつか用意して、足し算ができているか確かめてみましょう。@mainアノテーションでmainメソッド手軽に定義できるのもScala3のいいところですね。enum NatのZeroSuccなどのcaseを参照する場合は、import Nat.*とすることで可能です。import Nat._と書いても動きますが、Bookやドキュメントは*を使っているので、そのほうがお行儀が良さそうです。

import Nat.*
val one = Succ(Zero)
val two = Succ(one)
val three = Succ(two)

@main def main: Unit =
  println(three)                   // Succ(Succ(Succ(Zero)))
  println(plus(one, two) == three) // true

せっかくなのでElmでも書かせてください。これであなたは、ElmもScala3もマスター!

type Nat
    = Zero
    | Succ Nat


plus : Nat -> Nat -> Nat
plus left right =
    case ( left, right ) of
        ( Zero, r ) ->
            r

        ( l, Zero ) ->
            l

        ( Succ pl, r ) ->
            Succ <| plus pl r

Discussion