(define lambda

(native_function "
  Proc.new() do |arguments, interpreter|
    formals = arguments[0]
    body = arguments.slice(1, arguments.length)

    if formals.is_a? Array
      # detect if any formal names have been used more than once
      error_message = 'Formal {FORMAL} declared more than once' 
      formals.each_index do |x| 
        tmp = formals.dup
        tmp.delete_at(x)
        raise(error_message.gsub('{FORMAL}', formals[x])) if tmp.include? formals[x] 
      end
    end

    sub_env = Flea::Environment.new(interpreter.current_environment)

    execute_body = Proc.new() do |body, environment, interpreter|
      interpreter.current_environment = environment
      result = nil
      body.each do |expression|
        result = interpreter.evaluate(expression)
      end
      interpreter.current_environment = environment.parent
      result
    end    

    if formals.is_a?(Array) && formals.include?(:'.')
      Proc.new() do |arguments, interpreter|
        args = arguments.dup
        named_formals = formals.slice(0, formals.index(:'.'))
        list_formal = formals[formals.index(:'.') + 1]
        named_formals.each_index do |i|
          sub_env.define(named_formals[i], interpreter.evaluate(args.shift))
        end
        sub_env.define(list_formal, args)
        execute_body.call(body, sub_env, interpreter)
      end

    elsif formals.is_a? Array
      Proc.new() do |arguments, interpreter|
        formals.each_index do |i|
          sub_env.define(formals[i], interpreter.evaluate(arguments[i]))
        end
        execute_body.call(body, sub_env, interpreter)
      end

    elsif formals.is_a? Symbol
      Proc.new() do |arguments, interpreter|
        arguments = arguments.map {|x| interpreter.evaluate(x) }
        sub_env.define(formals, arguments)
        execute_body.call(body, sub_env, interpreter)
      end
    end
  end
"))