ScalaのAuxパターン

ScalaにはAuxパターンというものがあるらしいのでまとめ。

解決したい課題

ある型に対しての型クラスインスタンスが複数欲しいときがあり、しかもその型クラス同士に依存関係があるとする。

trait TypeClass[T] {
  type R
}

def something[T](implicit tc: TypeClass[T], Monad[tc.R]}: tc.R

上の例でいくとsomethingメソッドはTのTypeClassインスタンスが必要だ。
しかもTypeClass[T]がもつRをdependent typeで解決してそのRに対してのMonadインスタンスが必要である。

しかしこれはコンパイルが通らない。
なぜかと言うとScalaでは同じパラメタブロックに対してのdependent typeを許していない。

これを解決するのがAuxパターン。

Auxパターンの使い方

上の例に追加でtype aliasを追加し、somethingのメソッドシグネチャを少し変更する。

trait TypeClass[T] {
  type R
}

object TypeClass {
  type Aux[T0, R0] = TypeClass[T0] { type R = R0 }
}

def something[T, R](implicit tc: TypeClass.Aux[T, R], Monad[R]): R

つまりどういうことかと言うと今までTypeClass内にいたRを型パラメタとして表に引っ張り出してきたのだ。
これによってdependent typeを使わずとも型クラスインスタンス同士の関係性が表現できる。
また少し混乱するがシグネチャにある通り TypeClass.Aux[T, RR] == TypeClass[T] { type R = RR }である。
なので変更前と必要となる型クラスのインスタンスは変わっていない。

ちなみにこの問題はdottyで解決される。

参考

https://www.slideshare.net/TaisukeOe/auxdotty
https://gigiigig.github.io/posts/2015/09/13/aux-pattern.html
https://github.com/milessabin/shapeless/blob/d375218ce8a879ccf1d2071aa5a60dda9c2b97d7/core/src/main/scala/shapeless/generic.scala#L117

TypeScriptとHigher Kinded Type(高階型) TypeScriptと型クラス Ordersky先生が説明してくれたdottyに入るかもしれないchecked exceptionのモチベ
View Comments
There are currently no comments.