昔のQuickCheckのArbitraryにはcoarbitraryメソッドがあった件

標題のことに今更気がついて、少し想定外だったので、それをメモするだけのものです。


O'ReillyのHaskellのやつ(Real Workd Haskell)


Real World Haskell―実戦で学ぶ関数型言語プログラミング

Real World Haskell―実戦で学ぶ関数型言語プログラミング



をかなり久しぶりに見返していたら、以下のような記述がありました(268ページ)


このクラスはcoarbitraryメソッドも定義しています。これはある型の値を与えると、新しい生成器のための関数を作ります。これはさしあたり無視できます。これが必要になるのは関数の型のランダムな値を生成するときだけだからです。
coarbitraryを無視すると、GHCはcoarbitraryが定義されていないと警告を発します。しかし、この警告は無視しても大丈夫です。


"このクラス" とは Arbitrary クラスのことです。Real World Haskellはある程度古いので、Quickcheck1で書かれてるようです。
自分も詳細には知りませんが、QuickCheckは、大きく分けるとversion 1とversion 2があるようです。

現在のQuickcheck2のリポジトリは以下のgithubですが

https://github.com/nick8325/quickcheck

一番最初のコミット見ても、その形*1ではなく、CoArbitraryクラスは分かれていますね。

https://github.com/nick8325/quickcheck/commit/d4ed13fdddba5f8261a

ところで、quickcheck2の最初のコミットが2006年て、だいぶ昔ですね・・・。
どうでもいい余談としては、2006年といえば、自分は全くプログラミングやってなくて、大学2年くらい?で、書道やりつつ、中国語とか美学とか哲学とか芸術の勉強してました・・・。


さて、hackageからたどると、たしかにQuickCheck 1のソースコードも見れて、coarbitraryがArbitraryクラスに定義されています

class Arbitrary a where
  arbitrary   :: Gen a
  coarbitrary :: a -> Gen b -> Gen b


なぜこれがわざわざblog書くほど気になるか?というと、以前勉強会で発表したように

ScalaにおいてCoArbitraryを持ったテストライブラリが存在しなかったから、色々調べてライブラリ作ってしまったなどの経緯があるからですね。


しかも、pocketberserkerさんの CoArbitraryの実装比較 という記事で

idris-quickcheck

https://github.com/david-christiansen/idris-quickcheck/blob/51b7f619a3203c20ef8d8e30007bd83dba9fd386/QuickCheck.idr#L96

Arbitrary がほしいなら双対も一緒に定義しろ、という潔さです。


という記述がありました。


つまり(?)気になる点をまとめると

  • 個人的に、Arbitraryクラスでcoarbitraryを要求したほうがいいのか?した場合のメリットデメリットがわかってないので整理したい
  • QuickCheckは、なぜcoarbitraryを分けたのか?の理由を知りたい
    • 気が向けば自分で調べますが、誰が知ってたら教えてください。理由が書いてある資料のリンクだけでもいいので
  • そもそも、(APIの使い勝手はある程度無視して) 数学的に「arbitraryが定義できればcoarbitraryも必ず定義できる」みたいなことは言えるのか?
  • Idrisは、単に古いQuickCheckを真似てそうなったのか、古いQuickCheckとはあまり関係なく、なにか理由があってcoarbitraryも一緒にしたのか?
  • QuickCheckそのものの歴史というかライブラリの変遷も気になりだしたので、知っておきたい
  • Idrisと古いQuickCheck以外で、この方法(一緒に定義する方法)で定義してる実装存在するのだろうか?


あたりでしょうか。
気が向いたらそのあたりこれから調べたい、というメモなので、これ以上結論はないです。
なにか判明したら、別エントリ書くかもしれません。

*1:Arbitraryクラスにcoarbitraryメソッドがある