pexels-photo-884788.jpeg

ScalaのAuxパターン

 
0
このエントリーをはてなブックマークに追加
Kazuki Moriyama
Kazuki Moriyama (森山 和樹)

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

info-outline

お知らせ

K.DEVは株式会社KDOTにより運営されています。記事の内容や会社でのITに関わる一般的なご相談に専門の社員がお答えしております。ぜひお気軽にご連絡ください。