1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Scala の shapeless について(Poly1, Coproduct, Generic)

Posted at

はじめに

今回の記事では、Scala の generic ライブラリである shapeless について調べてみたことをアウトプットしていきます。
誤っている点がございましたらコメントいただけると嬉しいです。

shapeless とは

shapelessは、Scalaの型クラスと従属型に基づいた汎用プログラミングライブラリです。
https://github.com/milessabin/shapeless

この説明だと想像がつきづらいので、次項から主要概念に触れていきたいと思います。

scala プロジェクトに導入する際は、scala のバージョンを 2.11.x ~ 2.13.x に設定し、 build.sbt に下記を追加する必要があるようです。

scalaVersion := "2.13.5"
libraryDependencies ++= Seq(
  "com.chuusai" %% "shapeless" % "2.3.3"
)

Poly1

Shapelessは多相関数を表現するためにPolyという型を提供している。Polyはパラメータの型に依存して結果の型が決まる。
https://books.underscore.io/shapeless-guide/shapeless-guide.html#polymorphic-functions

ポリモーフィズムという考え方が適用されていて、変換するという意味では scala の Tuple や Function と似ているが、扱い方は異なるそう。
型固有のケースを捉えることができるため、ジェネリックプログラミングに最適な変換が可能となるみたいです。

object size extends Poly1 {
  implicit def caseInt = at[Int](x => 1)
  implicit def caseString = at[String](_.length)
  implicit def caseTuple[T, U]
    (implicit st : Case.Aux[T, Int], su : Case.Aux[U, Int]) =
      at[(T, U)](t => size(t._1)+size(t._2))
}
scala> size(23)
res4: Int = 1
scala> size("foo")
res5: Int = 3
scala> size((23, "foo"))
res6: Int = 4
scala> size(((23, "foo"), 13))
res7: Int = 5

また、Poly 型には、Poly1~Poly22 のサブタイプがあるようです。

Coproduct

shapelessはScalaのEitherを一般化したCoproduct型を持ち、任意の数の選択肢を持つことができる。現在のところ、Coproductはマッピング、選択、単一化をサポートしている。
https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#coproducts-and-discriminated-unions

scala の Either に似ているようで、こちらも概念的には別物で、unionと言われる共用体の方が意味合い的には近いようです。
https://ja.wikipedia.org/wiki/%E5%85%B1%E7%94%A8%E4%BD%93

scala> type ISB = Int :+: String :+: Boolean :+: CNil
defined type alias ISB

scala> val isb = Coproduct[ISB]("foo")
isb: ISB = foo

scala> isb.select[Int]
res0: Option[Int] = None

scala> isb.select[String]
res1: Option[String] = Some(foo)

一般的に、 A :+: B :+: C :+: CNi の形をとり、「A または B または C」を意味します。

Generic

ShapelessはGenericという型クラスを提供し、具象 ADT とその総称表現の間を行き来することを可能にしている。裏技的なマクロを使えば、定型文なしでGenericのインスタンスを呼び出すことができる。
https://books.underscore.io/shapeless-guide/shapeless-guide.html#switching-representations-using-generic

import shapeless.Generic

case class IceCream(name: String, numCherries: Int, inCone: Boolean)
val iceCreamGen = Generic[IceCream]
// iceCreamGen: shapeless.Generic[IceCream]{type Repr = String :: Int :: Boolean :: shapeless.HNil} = anon$macro$4$1@6b9323fe

インスタンスは、Repr がつきまとう。

おわりに

ここまで shapeless の Poly1, Coproduct, Generic について触れてみましたが、実装に落とし込めるほど理解できていないので、これからも学習を続けていきます。

参考にした記事

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?