Skip to content
This repository has been archived by the owner on Nov 11, 2021. It is now read-only.

Generator をユーザーが手軽にコントロールする為のユーティリティなどの実装 #3

Open
VoQn opened this issue May 21, 2012 · 4 comments
Milestone

Comments

@VoQn
Copy link
Collaborator

VoQn commented May 21, 2012

Haskell でのインターフェース

Test.QuickCheck.Gen で用意されている、ジェネレーターのコントローラ

sized :: (Int -> Gen a) -> Gen a


resize :: Int -> Gen a -> Gen a

-- ランダムに値を生成できる2つの値の組から、その範囲内のジェネレーターを作る
choose :: Random a => (a, a) -> Gen a

-- 外部入力やリソースから読み込んだジェネレーターを、テストに利用できるようにする
promote :: Monad m => m (Gen a) -> Gen (m a)

-- ジェネレーターを「生成された値が特定の条件に合うように」加工する
suchThat :: Gen a -> (a -> Bool) -> Gen a

-- ジェネレーターを「生成された値が特定の条件に合うなら Just, 合わなければ Nothing に」加工する
suchThatMaybe :: Gen a -> (a -> Bool) -> Gen (Maybe a)

-- ジェネレーターのリストから、一つ選ぶ
oneof :: [Gen a] -> Gen a

-- [(比率, ジェネレーター)] のリストから、偏りがあるようにジェネレーターを選ぶ
frequency :: [(Int, Gen a)] -> Gen a

-- リストの中から一個
elements :: [a] -> Gen a

-- 無限リストからジェネレーターを作る
growingElements :: [a] -> Gen a

-- ジェネレーターから、空リストを含む、リストのジェネレーターを作る
listOf :: Gen a -> Gen [a]

-- 空じゃない(最少でも一個は要素のある)リストのジェネレーターを作る
listOf1 :: Gen a -> Gen [a]

-- 固定長リスト
vectorOf :: Int -> Gen a -> Gen [a]

JavaScript で書くとこういう感じ

var env = (function(){
  var seed = 0; // 乱数生成の為のシード。説明を簡易に済ます為に、ここでは 2 の指数だとする
  return { // テストの為の環境変数のようなモノを模擬的に用意している。
    getSeed: function(){ // シードは readonly
      return seed;
    },
    growSeed: function(){ // シードをインクリメントして乱数が大きくなるようにする
      seed++;
    },
    random: function( type ){ // seed から、引数のタイプに合わせてプリミティブのランダムを用意する
      var genNum = function(){ // 非負の数値のランダム
         return Math.min( Number.MAX_VALUE, Math.random() * Math.pow( 2, seed ));
      };
      var genSign = function(){ // 正負の係数をランダムで
         return Math.random() > 0.5 ? (-1) : 1;
      };
      var genChar = function(){
         return String.fromCharCode( 0x40 + genNum().ceil() );
      };
      if ( !!type ) return genSign() * genNum(); // 引数指定無い場合はデフォルト
      switch ( type ) {
        case 'boolean': return genSign() == -1;
        case 'int': return genSign() * genNum().ceil();
        case 'char': genChar();
        default: return genSign() * randomNum();
      }
    },
    clear: function(){ // テスト環境初期化
      seed = 0;
    }
  };
})();

var choose = function( minSeed, maxSeed ) {
  return function(){
   return minSeed + Math.random() * maxSeed + 1;
  };
}

var elements = function( list ) {
  return function(){
    return list[ choose( 0, list.length - 1 )() ]
  }();
}

var oneof = function( generators_list ) {
  return elements( generators_list );
};

var _genArray = function( generator, length, shouldNotEmpty ){
  var len = length || Math.abs( env.random( 'int' ) ); // 配列長が引数で決まらない場合は テスト環境オブジェクトに決めてもらう
  if ( shouldNotEmpty ) {
    len = Math.max( 1, len );
  }
  return function(){
     var i = 0, result = [];
     for( ; i < len; i++){
       result[ i ] = generator();
     }
     return result;
  };
};

var listOf = function( generator ){
  return _genArray( generator );
};

var listOf1 = function( generator ){
  return _genArray( generator, undefined, true );
};

var vectorOf = function( length, generator ){
   return _genArray( generator, length );
};
@VoQn
Copy link
Collaborator Author

VoQn commented May 21, 2012

なんか quickcheck.js 先に実装すませた方が開発進行良いのではって気がしてきた

@yaakaito
Copy link
Owner

まあなんか読みつつ

@VoQn
Copy link
Collaborator Author

VoQn commented May 24, 2012

乱数生成の seed に影響が無いやつ、こんな感じで書けたわ

var choose = function( low, high ){
  return function(){
    var l = Math.random() * low
       , h = Math.random() * high
       , i = l + h
       , r = Math.min( high, Math.max( low, i ));
    return r;
  };
};
var elements = function( list ){
  return function(){
    var index = Math.round( choose( 0, list.length - 1 )() )
       , item = list[ index ];
    return item;
  };
};
var oneOf = function( generators ){
  var generator = elements( generators );
  return generator;
};

@yaakaito
Copy link
Owner

resize elements choose が実装済み

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants