LoginSignup
3
3

More than 5 years have passed since last update.

shapeless - Sized

Last updated at Posted at 2016-01-06

Sizedとは

Listとかをラップして静的な長さを持つもの。

Sizedの定義
final class Sized[+Repr, L <: Nat] private (val unsized : Repr) extends AnyVal {
  override def toString = unsized.toString
}

Reprはコレクションの型で、Lは要素の数(Nat)だ。Natに関してはこっちに記事書いてある。

試しに使ってみる。

scala> import shapeless._
import shapeless._

scala> val s = Sized(1,2,3)
//s: shapeless.Sized[scala.collection.immutable.IndexedSeq[Int],shapeless.nat._3] = Vector(1, 2, 3)

scala> s(0)
//res1: Int = 1

scala> s(1)
//res2: Int = 2

scala> s(2)
//res3: Int = 3

scala> s(3)
//<console>:15: error: could not find implicit value for parameter diff: shapeless.ops.nat.Diff[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]],shapeless.Succ[nat_$macro$4.N]]
//       s(3)
//        ^

静的に型を保持してるので、存在しないindexを取得するとコンパイルエラーに。
他にもいくつかメソッドが用意されている。

scala> s.head
//res8: Int = 1

scala> s.tail
//res9: shapeless.Sized[scala.collection.immutable.IndexedSeq[Int],shapeless.Succ[shapeless.Succ[shapeless._0]]] = Vector(2, 3)

scala> 0 +: s
//res10: shapeless.Sized[scala.collection.immutable.IndexedSeq[Int],shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]] = Vector(0, 1, 2, 3)

scala> s.take(2)
//res11: shapeless.Sized[scala.collection.immutable.IndexedSeq[Int],shapeless.Succ[shapeless.Succ[shapeless._0]]] = Vector(1, 2)

ちゃんと型も指定できる。List/Array/Stream等大体対応している。

scala> Sized[List](1,2,3)
//res25: shapeless.Sized[List[Int],shapeless.nat._3] = List(1, 2, 3)

文字列の長さにも対応している。

scala> Sized.wrap[String, nat._3]("abc")
//res26: shapeless.Sized[String,shapeless.nat._3] = abc

指定の長さかチェックしてOptionで返すことも。

scala> import syntax.sized._
//import syntax.sized._

scala> List(1,2,3).sized(3)
//res37: Option[shapeless.Sized[List[Int],shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]] = Some(List(1, 2, 3))

scala> List(1,2,3).sized(4)
//res38: Option[shapeless.Sized[List[Int],shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]]] = None

scala> "abc".sized(3)
//res39: Option[shapeless.Sized[String,shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]] = Some(abc)

scala> "abc".sized(4)
//res40: Option[shapeless.Sized[String,shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]]]] = None

あとHListやTuple等からも変換できる。

scala> (1::2::3::HNil).toSized[List]
//res42: shapeless.Sized[List[Int],shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]] = List(1, 2, 3)

scala> import syntax.std.tuple._
//import syntax.std.tuple._

scala> (1,2,3).toSized[List]
//res43: shapeless.Sized[List[Int],shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]] = List(1, 2, 3)

sizedのexampleには、csvのヘッダとボディで列の数が同じかを保証できるようになっている。
例を抜き出してみた。

scala> def csv[N <: Nat](hdrs : Sized[Seq[String], N], rows : List[Sized[Seq[String], N]]) = true
//csv: [N <: shapeless.Nat](hdrs: shapeless.Sized[Seq[String],N], rows: List[shapeless.Sized[Seq[String],N]])Boolean

scala> csv(Sized("id", "name"), List(Sized("1", "name1"), Sized("2", "name2")))
//res21: Boolean = true

scala> csv(Sized("id", "name"), List(Sized("1", "name1"), Sized("2")))
//<console>:16: error: no type parameters for method csv: (hdrs: shapeless.Sized[Seq[String],N], rows: List[shapeless.Sized[Seq[String],N]])Boolean exist so that it can be applied to arguments (shapeless.Sized[scala.collection.immutable.IndexedSeq[String],shapeless.nat._2], List[shapeless.Sized[scala.collection.immutable.IndexedSeq[String], _ >: shapeless.Succ[shapeless._0] with shapeless.Succ[shapeless.Succ[shapeless._0]] <: shapeless.Succ[_ >: shapeless._0 with shapeless.Succ[shapeless._0] <: Serializable with shapeless.Nat{type N >: shapeless._0 with shapeless.Succ[shapeless._0] <: Serializable with shapeless.Nat}]]])

Listの長さが同じでないとコンパイルエラーになる。

便利ですね(∩´ᵕ`∩)

3
3
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
3
3