Test.LeanCheck.Coreはコメントを除いて 185 行くらい)> holds 100 $ \xs-> sort (sort xs) == sort (xs :: [Int])
True
Showクラスのインスタンスを提供している(個人的には下の二つが面白いと思った)
(leancheck4s という名前が
当時はなぜか思い付かなかった‥‥)
Intなどの整数、Doubleなどの浮動小数点数、scala> import codes.quine.leanprops._
import codes.quine.leanprops._
scala> inspect { (x: Boolean, y: Boolean) => x && y }
res0: String =
((x, y) => (x, y) match {
case (true, true) => true
case _ => false
})
scala> holds(100) { (xs: List[Int]) =>
| xs.sorted.sorted == xs.sorted
| }
res1: Boolean = true
trait Listable[A]:Aが自動生成可能なことを表す型クラスtrait Inspectable[A]:Aが文字列にして表示可能なことを表す型クラスclass Tiers[A]:Stream[Seq[A]]をラップしたデータ構造class WithInspectConfig[A]:InspectConfigを持った Reader Monad一番重要なのはtrait Listable[A]。
trait Listable[A]trait Listable[A] {
def tiers: Tiers[A]
}
Tiers[A]はStream[Seq[A]]のラッパStream[A]ではなくStream[Seq[A]]なのはStream[A]じゃダメ?仮にListable[A]がこうだったとする。
trait Listable[A] {
def list: Stream[A]
}
list[A] = Listable[A].listとする。
Stream[A]じゃダメ?list[Int] = Stream(0, 1, -1, ...)
そこでlist[(A, B)]を考えると、単純な実装だと‥
list[(A, B)] = for {
x <- list[A]
y <- list[B]
} yield (x, y)
Stream[A]じゃダメ?つまり、
Stream((list[A](0), list[B](0)),
(list[A](0), list[B](1)),
... (list[B]が終了するまで続く),
(list[A](1), list[B](0)),
...)
(Int, Int)の場合、
左側に0しか出てこなくなる。
Stream[A]じゃダメ?そこでtiers[A]: Stream[Seq[A]]を考える。
tiers[Int] = Stream(Seq(0), Seq(1), Seq(-1), ...)
tiers[(A, B)]は次のような感じ、
def prod[A, B](xs: Seq[A], ys: Seq[B]) = for (x <- xs; y <- ys) yield (x, y)
Stream(prod(tiers[A](0), tiers[B](0)), // 添字の合計が0
prod(tiers[A](0), tiers[B](1))
++ prod(tiers[A](1), tiers[B](0)), // 添字の合計が1
prod(tiers[A](0), tiers[B](2))
++ prod(tiers[A](1), tiers[B](1))
++ prod(tiers[A](2), tiers[B](0)), // 添字の合計が2
...)
こうすると、無限リストでもいい感じに積を取れる。
trait Listable[A]SetやMapの場合は重複しないように生成したり、Function1の場合はMapとほとんど同じなのだけど、(さすがに時間が無さそうなので三行で)
_で上手い具合に置き換えていく引数を自動生成できるんだから、
たくさん呼び出して返り値を記録すれば
それっぽいmatch式が作れるよね、というノリ。
trait Inspectable[A]trait Inspectable[A] {
def inspect(x: A): WithInspectConfig[A]
def bindtiers(x: Try[A]): Tiers[(Seq[Seq[String]], Try[String])]
}
このbindtiersが、引数と返り値を記録するメソッド。
scala> inspect { (xs: List[Int]) => xs.head }
res3: String =
(x => x match {
case List() => throw new NoSuchElementException("head of empty list")
case List(0) => 0
case List(0, 0) => 0
case List(1) => 1
case List(0, 0, 0) => 0
case List(0, 1) => 0
case List(1, 0) => 1
case List(-1) => -1
...
})
ぶっちゃけBooleanのときくらいしか上手くいかない。
Streamは難しすぎる。WithInspectConfigって名前どうなの?Listable、Inspectableのインスタンスを増やすcats・scalazの型のインスタンスを実装するshapelessでの自動導出sbtとの統合disciplineのようなインターフェース(?)