whole_func_string: function applyGenericOperatorIndex(r, schema, parent){
  	if(r.type === 'view'){
  
  		if(r.view === 'reducing-index') return r
  
  		if( r.view !== 'case' && r.view !== 'default' && //do not break switch statements
  			r.view !== 'map' && r.view !== 'multimap'// do not break mapValue(map()) exprs
  			&& r.view !== 'mapValue'
  			&& r.view !== 'property' //no point wrapping a redundant index
  			&& r.view !== 'cast' //no point TODO flip this to an explicit "heavy" tag that causes indexing
  			&& r.view !== 'type' //not worth it
  			&& r.view !== 'timestamp' //not worth it
  			&& r.view !== 'list' //not worth it
  			&& r.view !== 'isa' //not worth it
  			&& r.view !== 'not' //not worth it
  			&& r.view !== 'generic-operator-index' //obv
  			&& (!parent || parent.view !== 'generic-operator-index') //obv
  			&& !schema[r.view] //don't index object(id) lookups - they're a no-op anyway
  			){
  
  			var params = getParams(r, schema)
  			//console.log(r.view + ' ' + JSON.stringify(params))
  			//if(r.view !== 'property' || r.params[1] !== params[0]){
  				if(params.length === 1){
  				
  					if(canIndex(r, schema, params[0])){
  						//console.log('cannot index: ')
  						//if(r.view === 'tokenizeAndStemText') _.errout('TODO: ' + JSON.stringify(r, null, 2))
  						//return r
  					
  				
  						var indexExprs = getIndexes(r, params[0])
  						var res = {
  							type: 'view',
  							view: 'generic-operator-index',
  							params: [
  								params[0],
  								r
  							].concat(indexExprs),
  							schemaType: r.schemaType,
  							code: r.code
  						}
  						//console.log('res: ' + JSON.stringify(res, null, 2))
  						return res
  					}
  				}else if(params.length > 1 && r.params.length === 1 && r.params[0].view === 'property'){//there are multiple params in use, but they can be reduced to a single param via a 'let' externalization
  				
  					var name = 'extracted_for_goi_'+Math.random()
  					var expr = r.params[0].params[1]
  					var newParam = {type: 'param', name: name, schemaType: expr.schemaType, was: expr}
  					
  					var newPropertyExpr = {
  						type: 'view',
  						view: 'property',
  						params: [
  							r.params[0].params[0],
  							newParam
  						],
  						schemaType: r.schemaType
  					}
  					
  					var res = {
  						type: 'let',
  						//view: 'let',
  						expr: expr,
  						rest: {
  							type: 'view',
  							view: 'generic-operator-index',
  							params: [
  								newParam,
  								{
  									type: 'view',
  									view: r.view,
  									params: [newPropertyExpr],
  									schemaType: r.schemaType
  								},
  								newPropertyExpr
  							]
  						},
  						name: name,
  						schemaType: r.schemaType,
  						code: r.code
  					}
  					
  					//res.expr = applyGenericOperatorIndex(res.expr, schema)//?
  					
  					return res
  				}
  			//}
  		}
  		
  		if(r.view === 'tokenizeAndStemText') _.errout('TODO: ' + JSON.stringify(r, null, 2))
  
  		if(r.view === 'generic-operator-index') return r
  		
  		r.params.forEach(function(p,i){
  			r.params[i] = applyGenericOperatorIndex(p, schema, r)
  		})
  	}else if(r.type === 'let'){
  		r.expr = applyGenericOperatorIndex(r.expr, schema)
  		r.rest = applyGenericOperatorIndex(r.rest, schema)
  	}else if(r.type === 'macro'){
  		r.expr = applyGenericOperatorIndex(r.expr, schema)
  	}else if(r.type === 'param' || r.type === 'value' || r.type === 'int' || r.type === 'nil'){
  		//do nothing
  
  	}
  	if(r.view === 'tokenizeAndStemText') _.errout('TODO: ' + JSON.stringify(r, null, 2))
  	return r
  }
func_code_string: function applyGenericOperatorIndex(r, schema, parent){
  	if(r.type === 'view'){
  
  		if(r.view === 'reducing-index') return r
  
  		if( r.view !== 'case' && r.view !== 'default' && //do not break switch statements
  			r.view !== 'map' && r.view !== 'multimap'// do not break mapValue(map()) exprs
  			&& r.view !== 'mapValue'
  			&& r.view !== 'property' //no point wrapping a redundant index
  			&& r.view !== 'cast' //no point TODO flip this to an explicit "heavy" tag that causes indexing
  			&& r.view !== 'type' //not worth it
  			&& r.view !== 'timestamp' //not worth it
  			&& r.view !== 'list' //not worth it
  			&& r.view !== 'isa' //not worth it
  			&& r.view !== 'not' //not worth it
  			&& r.view !== 'generic-operator-index' //obv
  			&& (!parent || parent.view !== 'generic-operator-index') //obv
  			&& !schema[r.view] //don't index object(id) lookups - they're a no-op anyway
  			){
  
  			var params = getParams(r, schema)
  			//console.log(r.view + ' ' + JSON.stringify(params))
  			//if(r.view !== 'property' || r.params[1] !== params[0]){
  				if(params.length === 1){
  				
  					if(canIndex(r, schema, params[0])){
  						//console.log('cannot index: ')
  						//if(r.view === 'tokenizeAndStemText') _.errout('TODO: ' + JSON.stringify(r, null, 2))
  						//return r
  					
  				
  						var indexExprs = getIndexes(r, params[0])
  						var res = {
  							type: 'view',
  							view: 'generic-operator-index',
  							params: [
  								params[0],
  								r
  							].concat(indexExprs),
  							schemaType: r.schemaType,
  							code: r.code
  						}
  						//console.log('res: ' + JSON.stringify(res, null, 2))
  						return res
  					}
  				}else if(params.length > 1 && r.params.length === 1 && r.params[0].view === 'property'){//there are multiple params in use, but they can be reduced to a single param via a 'let' externalization
  				
  					var name = 'extracted_for_goi_'+Math.random()
  					var expr = r.params[0].params[1]
  					var newParam = {type: 'param', name: name, schemaType: expr.schemaType, was: expr}
  					
  					var newPropertyExpr = {
  						type: 'view',
  						view: 'property',
  						params: [
  							r.params[0].params[0],
  							newParam
  						],
  						schemaType: r.schemaType
  					}
  					
  					var res = {
  						type: 'let',
  						//view: 'let',
  						expr: expr,
  						rest: {
  							type: 'view',
  							view: 'generic-operator-index',
  							params: [
  								newParam,
  								{
  									type: 'view',
  									view: r.view,
  									params: [newPropertyExpr],
  									schemaType: r.schemaType
  								},
  								newPropertyExpr
  							]
  						},
  						name: name,
  						schemaType: r.schemaType,
  						code: r.code
  					}
  					
  					//res.expr = applyGenericOperatorIndex(res.expr, schema)//?
  					
  					return res
  				}
  			//}
  		}
  		
  		if(r.view === 'tokenizeAndStemText') _.errout('TODO: ' + JSON.stringify(r, null, 2))
  
  		if(r.view === 'generic-operator-index') return r
  		
  		r.params.forEach(function(p,i){
  			r.params[i] = applyGenericOperatorIndex(p, schema, r)
  		})
  	}else if(r.type === 'let'){
  		r.expr = applyGenericOperatorIndex(r.expr, schema)
  		r.rest = applyGenericOperatorIndex(r.rest, schema)
  	}else if(r.type === 'macro'){
  		r.expr = applyGenericOperatorIndex(r.expr, schema)
  	}else if(r.type === 'param' || r.type === 'value' || r.type === 'int' || r.type === 'nil'){
  		//do nothing
  
  	}
  	if(r.view === 'tokenizeAndStemText') _.errout('TODO: ' + JSON.stringify(r, null, 2))
  	return r
  }
func_documentation_string: /*
  function shouldIndex(r){//TODO set up with .heavy = true config of impls, then start using
  if(r.type === 'view'){
  if(r.view === 'typeset'){
  return false
  }else if(r.view === 'each' || r.view === 'map' || r.view === 'eachReduce'){
  return true
  }
  var should = false
  r.params.forEach(function(p){
  should = should || shouldIndex(p)
  })
  }else if(r.type === 'let'){
  return shouldIndex(r.expr, param) || shouldIndex(r.rest)
  }else if(r.type === 'macro'){
  return shouldIndex(r.expr, param)
  }else if(r.type === 'param'){
  return false
  }else if(r.type === 'value' || r.type === 'int' || r.type === 'nil'){
  return false
  }else{
  _.errout('TODO')
  }
  }