/**
 * Y Combinator Factorial 
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */
class YFact {
  // Integer function returning an integer
  // int -> int
  interface IntFunc { int apply(int n); }

  // Function on int function returning an int function
  // (int -> int) -> (int -> int)
  interface IntFuncToIntFunc { IntFunc apply(IntFunc f); };

  // Higher-order function returning an int function
  // F: F -> (int -> int)
  interface FuncToIntFunc { IntFunc apply(FuncToIntFunc x); }

  // Function from IntFuntToIntFunc to IntFunc
  // ((int -> int) -> (int -> int)) -> (int -> int)
  interface IntFuncToIntFuncToIntFunc { IntFunc apply(IntFuncToIntFunc r);};

  public static void main(String args[]) {
    System.out.println(
      // Y combinator
      (new IntFuncToIntFuncToIntFunc() { public IntFunc apply(final IntFuncToIntFunc r) {
      return (new FuncToIntFunc() {public IntFunc apply(final FuncToIntFunc f) {
          return f.apply(f); }})
	.apply(
          new FuncToIntFunc() { public IntFunc apply(final FuncToIntFunc f) {
  	      return r.apply(
                new IntFunc() { public int apply(int x) {
		  return f.apply(f).apply(x); }});}});}}

    ).apply(
        // Recursive function generator
        new IntFuncToIntFunc() { public IntFunc apply(final IntFunc f) {
          return new IntFunc() { public int apply(int n) {
	    if (n == 0) return 1; else return n * f.apply(n-1); }};}} 

    ).apply(
      // Argument
      Integer.parseInt(args[0])));
  }
}
