function createFactory( prng, idtypes, odtypes, policies, options ) {
	var OPTIONS;
	var i;

	if ( !isFunction( prng ) ) {
		throw new TypeError( format( 'invalid argument. First argument must be a function. Value: `%s`.', prng ) );
	}
	if ( !isMethodIn( prng, 'factory' ) ) {
		throw new TypeError( format( 'invalid argument. First argument must have a `%s` method.', 'factory' ) );
	}
	if ( !isCollection( idtypes ) ) {
		throw new TypeError( format( 'invalid argument. Second argument must be an array-like object. Value: `%s`.', idtypes ) );
	}
	for ( i = 0; i < idtypes.length; i++ ) {
		if (
			!isCollection( idtypes[ i ] ) ||
			idtypes[ i ].length < 1 ||
			!everyBy( idtypes[ i ], isDataType )
		) {
			throw new TypeError( format( 'invalid argument. Second argument must contain arrays of data types. Value: `%s`.', idtypes ) );
		}
	}
	if (
		!isCollection( odtypes ) ||
		odtypes.length < 1 ||
		!everyBy( odtypes, isDataType )
	) {
		throw new TypeError( format( 'invalid argument. Third argument must be an array of data types. Value: `%s`.', odtypes ) );
	}
	if ( !isObject( policies ) ) {
		throw new TypeError( format( 'invalid argument. Fourth argument must be an object. Value: `%s`.', policies ) );
	}
	if ( !isOutputDataTypePolicy( policies.output ) ) {
		throw new TypeError( format( 'invalid argument. Fourth argument must be an object having a supported output data type policy. Value: `%s`.', policies.output ) );
	}
	OPTIONS = {};
	if ( arguments.length > 4 ) {
		if ( !isPlainObject( options ) ) {
			throw new TypeError( format( 'invalid argument. Options argument must be an object. Value: `%s`.', options ) );
		}
		if ( hasOwnProp( options, 'order' ) ) {
			OPTIONS.order = options.order;
			if ( !isOrder( OPTIONS.order ) ) {
				throw new TypeError( format( 'invalid option. `%s` option must be a valid memory layout. Option: `%s`.', 'order', OPTIONS.order ) );
			}
		}
	}
	return factory;

	/**
	* Returns a function for generating pseudorandom values drawn from a binary PRNG.
	*
	* @private
	* @param {Options} [options] - function options
	* @param {PRNG} [options.prng] - pseudorandom number generator which generates uniformly distributed pseudorandom numbers
	* @param {*} [options.seed] - pseudorandom value generator seed
	* @param {*} [options.state] - pseudorandom value generator state
	* @param {boolean} [options.copy] - boolean indicating whether to copy a provided pseudorandom value generator state
	* @throws {TypeError} options argument must be an object
	* @throws {TypeError} must provide valid options
	* @throws {Error} must provide a valid state
	* @returns {Function} function for creating ndarrays
	*/
	function factory() {
		var random;
		var base;
		var opts;

		if ( arguments.length > 0 ) {
			opts = arguments[ 0 ];
			if ( !isPlainObject( opts ) ) {
				throw new TypeError( format( 'invalid argument. Options argument must be an object. Value: `%s`.', opts ) );
			}
			base = prng.factory( opts );
		} else {
			opts = {};
			base = prng;
		}
		random = new Random( base, idtypes, odtypes, policies, OPTIONS );
		if ( opts && opts.prng ) {
			setReadOnly( rand, 'seed', null );
			setReadOnly( rand, 'seedLength', null );
			setReadWriteAccessor( rand, 'state', constantFunction( null ), noop );
			setReadOnly( rand, 'stateLength', null );
			setReadOnly( rand, 'byteLength', null );
		} else {
			setReadOnlyAccessor( rand, 'seed', getSeed );
			setReadOnlyAccessor( rand, 'seedLength', getSeedLength );
			setReadWriteAccessor( rand, 'state', getState, setState );
			setReadOnlyAccessor( rand, 'stateLength', getStateLength );
			setReadOnlyAccessor( rand, 'byteLength', getStateSize );
		}
		setReadOnly( rand, 'PRNG', base.PRNG );
		setReadOnly( rand, 'assign', assign );
		return rand;

		/**
		* Returns an ndarray filled with pseudorandom values drawn from a binary PRNG.
		*
		* @private
		* @param {NonNegativeIntegerArray} shape - output ndarray shape
		* @param {(ndarrayLike|*)} param1 - first PRNG parameter
		* @param {(ndarrayLike|*)} param2 - second PRNG parameter
		* @param {Options} [options] - function options
		* @param {string} [options.dtype] - output data type
		* @param {string} [options.order] - memory layout (either row-major or column-major)
		* @param {string} [options.mode] - specifies how to handle indices which exceed ndarray dimensions
		* @param {StringArray} [options.submode] - specifies how to handle subscripts which exceed ndarray dimensions on a per dimension basis
		* @param {boolean} [options.readonly] - boolean indicating whether an ndarray should be read-only
		* @throws {TypeError} first argument must be a valid shape
		* @throws {TypeError} must provide valid PRNG parameters
		* @throws {TypeError} PRNG parameters and the desired shape must be broadcast compatible
		* @throws {TypeError} options argument must be an object
		* @throws {TypeError} must provide valid options
		* @returns {ndarray} output array
		*/
		function rand( shape, param1, param2, options ) {
			if ( arguments.length < 4 ) {
				return random.generate( shape, param1, param2 );
			}
			return random.generate( shape, param1, param2, options );
		}

		/**
		* Fills an ndarray with pseudorandom values drawn from a binary PRNG.
		*
		* @private
		* @param {(ndarrayLike|*)} param1 - first PRNG parameter
		* @param {(ndarrayLike|*)} param2 - second PRNG parameter
		* @param {ndarrayLike} out - output ndarray
		* @throws {TypeError} third argument must be an ndarray
		* @throws {TypeError} must provide valid PRNG parameters
		* @throws {TypeError} PRNG parameters and the output ndarray must be broadcast compatible
		* @returns {ndarray} output ndarray
		*/
		function assign( param1, param2, out ) {
			return random.assign( param1, param2, out );
		}

		/**
		* Returns the PRNG seed.
		*
		* @private
		* @returns {*} seed
		*/
		function getSeed() {
			return rand.PRNG.seed;
		}

		/**
		* Returns the PRNG seed length.
		*
		* @private
		* @returns {PositiveInteger} seed length
		*/
		function getSeedLength() {
			return rand.PRNG.seedLength;
		}

		/**
		* Returns the PRNG state length.
		*
		* @private
		* @returns {PositiveInteger} state length
		*/
		function getStateLength() {
			return rand.PRNG.stateLength;
		}

		/**
		* Returns the PRNG state size (in bytes).
		*
		* @private
		* @returns {PositiveInteger} state size (in bytes)
		*/
		function getStateSize() {
			return rand.PRNG.byteLength;
		}

		/**
		* Returns the current pseudorandom value generator state.
		*
		* @private
		* @returns {*} current state
		*/
		function getState() {
			return rand.PRNG.state;
		}

		/**
		* Sets the pseudorandom value generator state.
		*
		* @private
		* @param {*} s - generator state
		* @throws {Error} must provide a valid state
		*/
		function setState( s ) {
			rand.PRNG.state = s;
		}
	}
}
Returns a function for generating pseudorandom values drawn from a binary PRNG.

@param {Function} prng - binary pseudorandom value generator
@param {Function} prng.factory - method which returns a new binary pseudorandom value generator
@param {ArrayLikeObject<StringArray>} idtypes - list containing a list of supported input data types for each PRNG parameter
@param {StringArray} odtypes - list of supported output data types
@param {Object} policies - policies
@param {string} policies.output - output data type policy
@param {Object} options - options
@param {string} options.order - default memory layout (either row-major or column-major)
@throws {TypeError} first argument must be a function
@throws {TypeError} first argument must have a `factory` method
@throws {TypeError} second argument must be an array containing arrays of supported data types
@throws {TypeError} third argument must be an array of supported data types
@throws {TypeError} fourth argument must be an object
@throws {TypeError} must provide valid options
@returns {Function} function which returns a function for creating arrays

@example
var dtypes = require( '@stdlib/ndarray/dtypes' );
var uniform = require( '@stdlib/random/base/uniform' );

var idt = dtypes( 'real_and_generic' );
var odt = dtypes( 'real_floating_point_and_generic' );

var policies = {
    'output': 'real_floating_point_and_generic'
};
var options = {
    'order': 'row-major'
};

var factory = createFactory( uniform, [ idt, idt ], odt, policies, options );

var rand = factory();
// returns <Function>

var v = rand( [ 2, 2 ], 0.0, 1.0 );
// returns <ndarray>

@example
var dtypes = require( '@stdlib/ndarray/dtypes' );
var ndzeros = require( '@stdlib/ndarray/zeros' );
var uniform = require( '@stdlib/random/base/uniform' );

var idt = dtypes( 'real_and_generic' );
var odt = dtypes( 'real_floating_point_and_generic' );

var policies = {
    'output': 'real_floating_point_and_generic'
};
var options = {
    'order': 'row-major'
};

var factory = createFactory( uniform, [ idt, idt ], odt, policies, options );

var rand = factory();
// returns <Function>

var out = ndzeros( [ 2, 2 ] );
var v = rand.assign( 0.0, 1.0, out );
// returns <ndarray>

var bool = ( v === out );
// returns true