@macro twice = fun(x) { x; x };
@macro max(x,y) {
  var _x = x; # no hygenic macro btw....
  var _y = y; # no hygenic macro btw....
  if(_x<_y){_y}else{_x}
};
def maxNormal(x,y) {
  if(x<y){y}else{x}
};
@macro maxBad(x,y) {
  if(x<y){y}else{x}
};

@macro LetItBe(x, y) { let it = x in y };

@macro pow10(x) {
  @value(
    def pow(y, n) {
      if( n == 1 ) { y }
      else {
        @macro( @value(y) * @value(pow(y,n-1)) )
      }
    }
    in
      pow(@macro(x+1),10)
  )
};

@macro pow10Hard(x) {
  @value(
    def pow(x, n) {
      if( n == 1 ) { x }
      else {
        @macro( @value(x) * @value(pow(x,n-1)) )
      }
    }
    in
      pow(@macro(x+1),10)
  )
};

def printAndReturn(x)
{
	print(x);
	x
};

def main()
{
	twice( print("foo") );
	print("--------------");
	print(max(printAndReturn(100),printAndReturn(200)));
	print("--------------");
	print(maxNormal(printAndReturn(100),printAndReturn(200)));
	print("--------------");
	print(maxBad(printAndReturn(100),printAndReturn(200)));
	print("--------------");
	print( LetItBe( 1+2+3, it*it ) );
	print("--------------");
	print(pow10(1));
	print(pow10(2));
	print("--------------");
	print(pow10Hard(1));
	print(pow10Hard(2));
};

main();

@macro foo(y)
{
	fun(y){y}(300)
#	let y = 300 in y
};

print("--------------");
print(foo(200));
