whole_func_string: function applyEachOptimization(rel){
  
  	var originalRel = rel
  	rel = JSON.parse(JSON.stringify(rel))	
  	
  	//console.log('rel: ' + JSON.stringify(rel))
  	try{
  		var newImplicits = [rel.params[1].implicits[0]]
  		var bindingsUsed = _.extend({}, rel.params[1].bindingsUsed)
  		//1. extract macro params to one or more ~:property maps
  		var maps = []
  		var failed = false
  		var newMacroExpr = replaceMacroPropertyExpressions(rel.params[1].expr, rel.params[1].implicits, function(macroPropertyExpr){
  			if(macroPropertyExpr.schemaType.type === 'map'){
  				failed = true
  				return
  			}
  			var uid = 'extproperty_'+Math.random()
  			var bu = {}
  			bu[uid] = true
  			var m = {
  				type: 'view', 
  				view: 'map', 
  				params: [
  					rel.params[0],
  					{	
  						type: 'macro', 
  						manyImplicits: 1, 
  						expr: {type: 'param', name: uid, schemaType: rel.params[0].schemaType.members}, 
  						bindingsUsed: bu, 
  						implicits: [uid], 
  						schemaType: rel.params[0].schemaType.members,
  						implicitTypes: [rel.params[0].schemaType.members]
  					},{
  						type: 'macro', 
  						manyImplicits: 1, 
  						expr: JSON.parse(JSON.stringify(macroPropertyExpr)), 
  						bindingsUsed: bu, 
  						implicits: [rel.params[1].implicits[0]], 
  						schemaType: macroPropertyExpr.schemaType,
  						implicitTypes: [rel.params[1].implicitTypes[0]]
  					}
  				], 
  				willBeOptimized: true,
  				uid: uid
  			}
  			m.schemaType = {type: 'map', key: m.params[1].schemaType, value: m.params[2].schemaType}
  			maps.push(applyEachOptimizationToView(m))
  			newImplicits.push(uid)
  			bindingsUsed[uid] = true
  			_.assertDefined(macroPropertyExpr.schemaType)
  			return {type: 'param', name: uid, schemaType: macroPropertyExpr.schemaType}
  		})
  		if(failed) return originalRel
  		var newMacro = {
  			type: 'macro',
  			expr: newMacroExpr,
  			manyImplicits: newImplicits.length,
  			implicits: newImplicits,
  			implicitTypes: [rel.params[0].schemaType.members],
  			bindingsUsed: bindingsUsed,//newImplicits
  			schemaType: newMacroExpr.schemaType
  		}
  		//console.log('created m: ' + JSON.stringify(newMacro, null, 2))
  		return {
  			type: 'view',
  			view: 'each-optimization',
  			params: [rel.params[0], newMacro].concat(maps),
  			schemaType: rel.schemaType,
  			code: rel.code
  		}
  	}catch(e){
  		//console.log('could not optimize each + e.stack)
  		return originalRel
  	}
  }
func_code_string: function applyEachOptimization(rel){
  
  	var originalRel = rel
  	rel = JSON.parse(JSON.stringify(rel))	
  	
  	//console.log('rel: ' + JSON.stringify(rel))
  	try{
  		var newImplicits = [rel.params[1].implicits[0]]
  		var bindingsUsed = _.extend({}, rel.params[1].bindingsUsed)
  		//1. extract macro params to one or more ~:property maps
  		var maps = []
  		var failed = false
  		var newMacroExpr = replaceMacroPropertyExpressions(rel.params[1].expr, rel.params[1].implicits, function(macroPropertyExpr){
  			if(macroPropertyExpr.schemaType.type === 'map'){
  				failed = true
  				return
  			}
  			var uid = 'extproperty_'+Math.random()
  			var bu = {}
  			bu[uid] = true
  			var m = {
  				type: 'view', 
  				view: 'map', 
  				params: [
  					rel.params[0],
  					{	
  						type: 'macro', 
  						manyImplicits: 1, 
  						expr: {type: 'param', name: uid, schemaType: rel.params[0].schemaType.members}, 
  						bindingsUsed: bu, 
  						implicits: [uid], 
  						schemaType: rel.params[0].schemaType.members,
  						implicitTypes: [rel.params[0].schemaType.members]
  					},{
  						type: 'macro', 
  						manyImplicits: 1, 
  						expr: JSON.parse(JSON.stringify(macroPropertyExpr)), 
  						bindingsUsed: bu, 
  						implicits: [rel.params[1].implicits[0]], 
  						schemaType: macroPropertyExpr.schemaType,
  						implicitTypes: [rel.params[1].implicitTypes[0]]
  					}
  				], 
  				willBeOptimized: true,
  				uid: uid
  			}
  			m.schemaType = {type: 'map', key: m.params[1].schemaType, value: m.params[2].schemaType}
  			maps.push(applyEachOptimizationToView(m))
  			newImplicits.push(uid)
  			bindingsUsed[uid] = true
  			_.assertDefined(macroPropertyExpr.schemaType)
  			return {type: 'param', name: uid, schemaType: macroPropertyExpr.schemaType}
  		})
  		if(failed) return originalRel
  		var newMacro = {
  			type: 'macro',
  			expr: newMacroExpr,
  			manyImplicits: newImplicits.length,
  			implicits: newImplicits,
  			implicitTypes: [rel.params[0].schemaType.members],
  			bindingsUsed: bindingsUsed,//newImplicits
  			schemaType: newMacroExpr.schemaType
  		}
  		//console.log('created m: ' + JSON.stringify(newMacro, null, 2))
  		return {
  			type: 'view',
  			view: 'each-optimization',
  			params: [rel.params[0], newMacro].concat(maps),
  			schemaType: rel.schemaType,
  			code: rel.code
  		}
  	}catch(e){
  		//console.log('could not optimize each + e.stack)
  		return originalRel
  	}
  }
func_documentation_string: takes the rel for the each