@Override
	public Expr apply(Expr[] args, InterpContext ctx) throws RuntimeError {
		Env locals = new Env(env);
		// 对实参求值
		for (int i = 0; i < args.length; i++) {
			args[i] = args[i].eval(ctx);
		}

		// 绑定固定参数
		for (int i = 0; i < fixed.length; i++) {
			locals.put(fixed[i], args[i]);
		}
		// 绑定可变参数
		Expr[] varargs = Arrays.copyOfRange(args, fixed.length, args.length);
		locals.put(var, list(varargs));

		if (traced) {
			Expr t = car(callexp); // retrive function name
			t = cons(t, list(args));
			for (int i = callcount; i > 0; i--) {
				System.out.print(" |");
			}
			callcount++;
			System.out.println("call: " + t.display());
		}

		// 对函数体求值
		InterpContext newctx = new InterpContext(locals);
		Expr result = null;
		for (int i = 0; i < body.length; i++) {
			result = body[i].eval(newctx);
		}

		if (traced) {
			callcount--; // 返回时递减
			for (int i = callcount; i > 0; i--) {
				System.out.print(" |");
			}
			System.out.println("return: " + result.display());
		}

		return result;
	}