読者です 読者をやめる 読者になる 読者になる

scalacheckの内部構造をいじって遊んでみた

SPECIAL DAY Scala Hack-a-son 143th in KABUKIZA - Scala Meetup Group in Tokyo | Doorkeeper

たまにはハッカソンもいいかなと思って参加してみました(噂の rpscala に参加してみたかったというのもある)。

で、当日は scalacheck をいじっていたコードがようやくテストに通るようになったので書き残しておきます。

注意事項

この記事のコードは pull request を送るつもりはないので、そのことを認識して読んでください。

今のところ scalacheck を fork して別プロジェクトとして育てるつもりもないです。

やりたかったこと

基本方針は "いらないものを消す" です。

  1. scalajs の クロスコンパイル設定を有効にする
  2. Gen で Option[T] ではなく T を返すようにする
  3. 内部表現 R trait を削除する
  4. scalaz で置き換えられそうなコードを置き換える
  5. ランダムを rng か spire/random に差し替える

現時点でできたのは R を消すまでです。

ロスコンパイル設定

https://github.com/pocketberserker/scalacheck/commit/c7c47204c7245d1a9830aca79b8550b9e63052fc

2015/02/12 時点の scalacheck の master ブランチは Windows 上ではそのままだとビルドできません。 クロスコンパイルのためのコード共有を、Windows で認識できないシンボリックリンクで行っているためです*1

対処法は sbt-scalajs の要求にあわせてディレクトリ構成変えたり設定変更した程度です。

これに関してはハッカソンの数日前に作業してました。

Gen で T を返す & R trait を削除する

https://github.com/pocketberserker/scalacheck/commit/6d03207ceee9caf6a9e7ad2cb518c532372bd826

quickcheck 系でデータの生成に失敗することはそうそうないので、 Option を返さないようにしました。

…が、ここで suchThat メソッドの実装でスタックオーバーフローしたり無限ループに陥ったりして、全然進まず。 結局当日の進捗は駄目でした。

後日、よく考えたら一部実装の変更に伴い suchThat を呼び出すべきではない部分を発見したので、これを削除したら動くようになりました。

R trait は Gen 用のラベルや sieve を持っているのですが、これもいらないだろうということで削除。

リファクタリングみたいなこと

https://github.com/pocketberserker/scalacheck/commit/e923d97a2ddfeb9b158bcb9524ce4ca844b7eb32

scala.util.Random から別のものに差し替えたいな、と思って依存関係だけ設定したのですが、作業できずじまい…。

Arbitrary 削除断念

CoArbitrary を自前実装してしまったので、消すのも変だなと思い残してます。

その他

値が生成できるまでがんばってしまうので、多少実行速度が劣化したような感覚… filtersuchThat のご利用は計画的に。

まとめ

rpscala は懇親会も含め楽しかったです。

*1:Windows にもシンボリックリンク自体は存在した気がする