Upgrade to Pro — share decks privately, control downloads, hide ads and more …

scalaprops

 scalaprops

kenji yoshida

July 25, 2015
Tweet

More Decks by kenji yoshida

Other Decks in Programming

Transcript

  1. 今日の内容 property based testing とscalacheck の簡単な説明 scalacheck の不満点とscalaprops 作成に至る経緯 scalaprops

    の紹介 主にHaskell の、その他様々なproperty based testing の手法紹介 6 / 152
  2. Scalacheck とは かなり古くからあるライブラリ(2007 年?) 単体でも使用可能だし、specs2 やscalatest と組み合 わせても可能 Scala 本体のテストにも使われている(

    コレクション など) 実質Scala 界隈で唯一のProperty Based Test のライ ブラリだったが、最近は新しいものを作る動きがい くつか 16 / 152
  3. バグ見つけるおじさんダヨー #scalaz special forces officer @xuwei_k once again demonstrates prowess

    tracking down insidious lawbreakers is.gd/mzUQUp 1:44 PM - Nov 17, 2013 1 See Stephen Compall's other Tweets Stephen Compall @S11001001 OptionT and LazyOptionT does not satisfy the "`a… xuwei-k/scalaz@7659278 rickynils/scalacheck#75 htt… github.com 27 / 152
  4. 「@xuwei_k は普通に読んでても気付かないような細かいバグ に気付いてる。どうやっているんだ? 」みたいなことを Scalaz の他のコミッタが nescala 後の懇親会で言ってた。あと「彼は nescala に来るべきだった」

    1:53 PM - Mar 11, 2014 3 See eugene yokota's other Tweets Mar 11, 2014 Kenji Yoshida @xuwei_k Replying to @xuwei_k まぁそもそもScalaz の開発が特にゆっくりというかそれほど互換 性壊す変更が急に入らないし、英語できないというのもあって妙 にコードだけで意図が伝わるように慎重にpull req する癖が他人よ りついたので、余計にあれ eugene yokota @eed3si9n_ja 28 / 152
  5. Align Functor Applicative Apply ApplicativePlus PlusEmpty Bind Cobind Comonad ComonadStore

    Contravariant InvariantFunctor Distributive Divide Divisible Foldab IsEmpty Monad MonadError MonadListen MonadTell MonadPlus MonadReader MonadState Plus Traverse Travers 32 / 152
  6.        ____         /     \ 関数をランダムに自動生成?     / 

     ⌒  ⌒ \   何言ってんだこいつ   /    (•)  (•) \   |    、"  ) (__ 人__ )"    )    \      。` ⌒´  , / _/           \  42 / 152
  7. scalaprops.Cogen abstract class Cogen[A] { def cogen[B](a: A, g: CogenState[B]):

    CogenState[B] } case class CogenState[A](rand: Rand, gen: Gen[A]) 44 / 152
  8. scalaprops の大雑把な歴史 2014 年以前 scalacheck に対する不満がたまり続ける 2015 年 2 月

    scalacheck にCoArbitrary 入れようと試し挫折 3 月 functional java をscala へ移植し始める 4 月 移植自体は大体できたが、実験や改良や新機能追加 5 月 0.1.0 公開 6 月 やること色々残ってたので週一ぐらいでリリース 7 月25 日現在0.1.11 が最新 47 / 152
  9. Scalaprops の機能 CoArbitrary(Cogen) 実装完了 タイムアウトとパラメータの細かい指定機能つけた seed 指定可能機能ついた immutable なメルセンヌツイスタ (scalaz

    の) 型クラスの重複テスト回避機能 最初からTree としてテストを階層構造化 Gen とArbitrary は、Gen だけにした 49 / 152
  10. package scalaprops import scalaz.IList import scalaz.std.anyVal._ object IListTest extends Scalaprops

    { val testLaws = Properties.list( scalazlaws.order.all[IList[Byte]], scalazlaws.monadPlusStrong.all[IList], scalazlaws.traverse.all[IList], scalazlaws.cobind.all[IList], scalazlaws.isEmpty.all[IList], scalazlaws.align.all[IList], scalazlaws.zip.all[IList] ) } https://github.com/scalaprops/scalaprops/tree/v0.1.13/scalaprops/src/test/scala/scalaprops/IListTest.scala 57 / 152
  11. Tree のscalaprops.Gen の定義つらい implicit def treeGen[A](implicit A: Gen[A]): Gen[Tree[A]] =

    { def loop(size: Int): Gen[Tree[A]] = size match { case n if n <= 1 => A.map(a => Tree.leaf(a)) case 2 => Gen[(A, A)].map{case (a1, a2) => Tree.node(a1, Stream(Tree.leaf(a2))) } case 3 => Gen[(A, A, A)].flatMap{case (a1, a2, a3) => Gen.elements( Tree.node(a1, Stream(Tree.leaf(a2), Tree.leaf(a3))), Tree.node(a1, Stream(Tree.node(a2, Stream(Tree.leaf(a3))))) ) } case _ => val max = size - 1 import scalaz.std.stream._ Applicative[Gen].sequence( Stream.fill(max)(Gen.choose(1, max - 1)) ).flatMap{s => val ns = Traverse[Stream].traverseS(s){ n => for{ sum <- State.get[Int] r <- if(sum >= max){ State.state[Int, Option[Int]](None) }else if((sum + n) > max){ State((s: Int) => (s + n) -> Option(max - sum)) }else{ State((s: Int) => (s + n) -> Option(n)) } } yield r }.eval(0).flatten Applicative[Gen].sequence(ns.map(loop)).flatMap(as => A.map(a => Tree.node(a, as)) ) } } Gen.sized(n => Gen.choose(0, n).flatMap(loop) ) } 71 / 152
  12. Tree のGen の生成の方法の例( つらい) ① 100 個以下の要素のTree 生成したい ② 0

    から 100 の間のランダム値N( たとえば80) を生成 ③ M をランダムに生成(80 に対してなんとなく小さめの 数字。たとえば5) ④ N をM 個にランダムに分割( たとえば、80 を12, 30, 3, 9, 26) ⑤ node1 は12 個、node2 は30 個・・・自身と子供を含 めて生成していいよ、みたいにする ⑥ ゼロになるまでそれぞれのnode で手順3 から繰り返 し 73 / 152
  13. scalaz 本体だともっと雑 implicit def TreeArbitrary[A: Arbitrary]: Arbitrary[Tree[A]] = import scalaz.Tree._

    def tree(n: Int): Gen[Tree[A]] = n match { case 0 => arbitrary[A] map (leaf(_)) case _ => { val nextSize = n.abs / 2 Apply[Gen].apply2(arbitrary[A], resize(nextSize, contain } } Gen.sized(tree _) } 76 / 152
  14. 例 Boolean => Boolean 2 の2 乗 = 4 通り

    Map(true -> true , false -> false) Map(true -> true , false -> true) Map(true -> false, false -> true) Map(true -> false, false -> false) 107 / 152
  15. Map(Some(true) -> true , Some(false) -> true , None ->

    true) Map(Some(true) -> true , Some(false) -> true , None -> false) Map(Some(true) -> true , Some(false) -> false, None -> true) Map(Some(true) -> true , Some(false) -> false, None -> false) Map(Some(true) -> false, Some(false) -> true , None -> true) Map(Some(true) -> false, Some(false) -> true , None -> false) Map(Some(true) -> false, Some(false) -> false, None -> true) Map(Some(true) -> false, Some(false) -> false, None -> false) 109 / 152
  16.        ____         /     \ 関数をShrink ?    

    /   ⌒  ⌒ \   何言ってんだこいつ   /    (•)  (•) \   |    、"  ) (__ 人__ )"    )    \      。` ⌒´  , / _/           \  115 / 152
  17. data a :-> c where Pair :: (a :-> (b

    :-> c)) -> ((a,b) :-> c) (:+:) :: (a :-> c) -> (b :-> c) -> (Either a b :-> c) Unit :: c -> (() :-> c) Nil :: a :-> c Table :: Eq a => [(a,c)] -> (a :-> c) Map :: (a -> b) -> (b -> a) -> (b :-> c) -> (a :-> c) 121 / 152
  18. sealed abstract class :->[A, B] case class Pair[A, B, C](a:

    A :-> (B :-> C)) extends (LazyTuple2[A, B] :-> C) case class :+:[A, B, C]( x: (A :-> C), y: (B :-> C) ) extends ((A \/ B) :-> C) case class Unit[A](a: A) extends (scala.Unit :-> A) case class Nil[A, B]() extends (A :-> B) case class Table[A: Equal, B]( a: Stream[LazyTuple2[A, B]] ) extends (A :-> B) case class Map[A, B, C]( x: A => B, y: B => A, z: (B :-> C) ) extends (A :-> C) 122 / 152
  19. SubHask SubHask is a radical rewrite of the Haskell Prelude.

    The goal is to make numerical computing in Haskell fun and fast. The main idea is to use a type safe interface for programming in arbitrary subcategories of Hask. 136 / 152
  20. ハスケル・カリーさん。wikipedia より ハスケル・ブルックス・カリー(Haskell Brooks Curry 、1900 年9 月12 日 -

    1982 年9 月1 日)はアメリカの数学者、論理学者。 マサチューセッツ州ミ リスで教育者サミュエル・サイラス・カリーの子として生まれる。ハーバ ード大学を卒業後、1930 年、ゲッティンゲン大学でダフィット・ヒルベル トに師事し、博士号を得た。 144 / 152