Что такое лямбда (функция)?

Что такое лямбда в мире компьютерных наук для человека без образования в области компьютерных наук?

Ответов (23)

Решение

Лямбда происходит от лямбда-исчисления и относится к анонимным функциям в программировании.

Почему это круто? Это позволяет вам писать быстро выбрасываемые функции, не называя их. Он также предоставляет удобный способ писать замыкания. С этой силой вы можете делать такие вещи.

Python

def adder(x):
    return lambda y: x + y
add5 = adder(5)
add5(1)
6

Как видно из фрагмента кода Python, сумматор функций принимает аргумент x и возвращает анонимную функцию или лямбду, которая принимает другой аргумент y. Эта анонимная функция позволяет вам создавать функции из функций. Это простой пример, но он должен передавать мощные лямбды и замыкания.

Примеры на других языках

Perl 5

sub adder {
    my ($x) = @_;
    return sub {
        my ($y) = @_;
        $x + $y
    }
}

my $add5 = adder(5);
print &$add5(1) == 6 ? "ok\n" : "not ok\n";

JavaScript

var adder = function (x) {
    return function (y) {
        return x + y;
    };
};
add5 = adder(5);
add5(1) == 6

JavaScript (ES6)

const adder = x => y => x + y;
add5 = adder(5);
add5(1) == 6

Схема

(define adder
    (lambda (x)
        (lambda (y)
           (+ x y))))
(define add5
    (adder 5))
(add5 1)
6

C# 3.5 или выше

Func<int, Func<int, int>> adder = 
    (int x) => (int y) => x + y; // `int` declarations optional
Func<int, int> add5 = adder(5);
var add6 = adder(6); // Using implicit typing
Debug.Assert(add5(1) == 6);
Debug.Assert(add6(-1) == 5);

// Closure example
int yEnclosed = 1;
Func<int, int> addWithClosure = 
    (x) => x + yEnclosed;
Debug.Assert(addWithClosure(2) == 3);

Быстрый

func adder(x: Int) -> (Int) -> Int{
   return { y in x + y }
}
let add5 = adder(5)
add5(1)
6

PHP

$a = 1;
$b = 2;

$lambda = fn () => $a + $b;

echo $lambda();

Haskell

(\x y -> x + y) 

Java см. Этот пост

// The following is an example of Predicate : 
// a functional interface that takes an argument 
// and returns a boolean primitive type.

Predicate<Integer> pred = x -> x % 2 == 0; // Tests if the parameter is even.
boolean result = pred.test(4); // true

Lua

adder = function(x)
    return function(y)
        return x + y
    end
end
add5 = adder(5)
add5(1) == 6        -- true

Котлин

val pred = { x: Int -> x % 2 == 0 }
val result = pred(4) // true

Рубин

Ruby немного отличается тем, что вы не можете вызывать лямбда-выражения, используя тот же синтаксис, что и вызов функции, но в нем все еще есть лямбда-выражения.

def adder(x)
  lambda { |y| x + y }
end
add5 = adder(5)
add5[1] == 6

Ruby - это Ruby, есть сокращение для lambdas, поэтому вы можете определить adder это так:

def adder(x)
  -> y { x + y }
end

р

adder <- function(x) {
  function(y) x + y
}
add5 <- adder(5)
add5(1)
#> [1] 6

Пример лямбды в Ruby выглядит следующим образом:

hello = lambda do
    puts('Hello')
    puts('I am inside a proc')
end

hello.call

Сгенерирует следующий вывод:

Hello
I am inside a proc

@Brian Я все время использую лямбды в C#, в операторах LINQ и не-LINQ. Пример:

string[] GetCustomerNames(IEnumerable<Customer> customers)
 { return customers.Select(c=>c.Name);
 }

До C# я использовал анонимные функции в JavaScript для обратных вызовов к функциям AJAX, еще до того, как появился термин Ajax:

getXmlFromServer(function(result) {/*success*/}, function(error){/*fail*/});

Однако интересная вещь с синтаксисом лямбда C# заключается в том, что их тип сам по себе не может быть передан (т.е. вы не можете ввести var foo = (x, y) => x * y), но в зависимости от того, какой тип они назначенные, они будут скомпилированы как делегаты или абстрактные синтаксические деревья, представляющие выражение (именно так средства отображения объектов LINQ делают свою «интегрированную в язык» магию).

Лямбда-выражения в LISP также можно передать оператору цитаты, а затем просмотреть в виде списка списков. Так создаются некоторые мощные макросы.

Мне нравится объяснение лямбда-выражений в этой статье: Эволюция LINQ и ее влияние на дизайн C# . Для меня это имело большой смысл, поскольку он показывает реальный мир лямбда-выражений и строит его в качестве практического примера.

Их краткое объяснение: лямбды - это способ рассматривать код (функции) как данные.

Просто потому, что я не вижу здесь примера C++ 11, я отправлю этот хороший пример отсюда . После поиска это самый ясный пример конкретного языка, который я смог найти.

Привет, лямбды, версия 1

template<typename F>

void Eval( const F& f ) {
        f();
}
void foo() {
        Eval( []{ printf("Hello, Lambdas\n"); } );
}

Привет, лямбды, версия 2:

void bar() {
    auto f = []{ printf("Hello, Lambdas\n"); };
    f();
}

В контексте CS лямбда-функция - это абстрактное математическое понятие, которое решает проблему символьного вычисления математических выражений. В этом контексте лямбда-функция - это то же самое, что и лямбда-член .

Но в языках программирования все по-другому. Это фрагмент кода, который объявлен «на месте» и может быть передан как «первоклассный гражданин». Эта концепция оказалась полезной, так что она вошла почти во все популярные современные языки программирования (см. Сообщение о лямбда-функциях в любом месте ).

На этот вопрос формально дан обширный ответ, поэтому я не буду пытаться добавлять по этому поводу больше.

Очень простыми, неформальными словами для человека, который очень мало или совсем ничего не знает о математике или программировании, я бы объяснил это как небольшую «машину» или «коробку», которая принимает какой-то ввод, выполняет некоторую работу и производит некоторый результат, не имеет конкретного названия. , но мы знаем, где он находится, и с помощью этого знания мы его используем.

Практически говоря, для человека, который знает, что такое функция, я бы сказал им, что это функция, у которой нет имени, обычно помещается в точку в памяти, которую можно использовать, просто ссылаясь на эту память (обычно через использование переменная - если они слышали о концепции указателей на функции, я бы использовал их как аналогичную концепцию) - этот ответ охватывает довольно основы (без упоминания замыканий и т. д.), но можно легко понять суть.

В компьютерном программировании лямбда - это фрагмент кода (оператор, выражение или их группа), который принимает некоторые аргументы из внешнего источника. Это не всегда должна быть анонимная функция - у нас есть много способов реализовать их.

У нас есть четкое разделение между выражениями, операторами и функциями, которых нет у математиков.

Слово «функция» в программировании тоже другое - у нас есть «функция - это последовательность действий, которые необходимо выполнить» (от латинского «выполнять»). В математике это что-то вроде корреляции между переменными.

Функциональные языки стараются быть максимально похожими на математические формулы, и их слова означают почти то же самое. Но в других языках программирования все по-другому.

Что такое лямбда в мире компьютерных наук для человека без образования в области компьютерных наук?

Я проиллюстрирую это интуитивно, шаг за шагом, на простых и удобочитаемых кодах Python.

Короче говоря, лямбда - это просто анонимная встроенная функция.

Начнем с задания, чтобы понять, lambdas как новичок с основами арифметики.

Схема присвоения - «имя = значение», см .:

In [1]: x = 1
   ...: y = 'value'
In [2]: x
Out[2]: 1
In [3]: y
Out[3]: 'value'

«x», «y» - это имена, а 1, «value» - значения. Попробуйте функцию в математике

In [4]: m = n**2 + 2*n + 1
NameError: name 'n' is not defined

Отчеты об ошибках,
вы не можете написать математику непосредственно в виде кода, n должно быть определено или присвоено значению.

In [8]: n = 3.14
In [9]: m = n**2 + 2*n + 1
In [10]: m
Out[10]: 17.1396

Теперь это работает, что, если вы настаиваете на объединении двух отдельных строк в одну. Идет lambda

In [13]: j = lambda i: i**2 + 2*i + 1
In [14]: j
Out[14]: <function __main__.<lambda>>

Об ошибках не сообщалось.

Это краткий обзор lambda, он позволяет вам записать функцию в одну строку, как вы это делаете в математике, прямо в компьютер.

Мы увидим это позже.

Давайте продолжим копать глубже в «назначении».

Как показано выше, символ равенства = работает для простого типа данных (1 и «значение») и простого выражения (n ** 2 + 2 * n + 1).

Попробуй это:

In [15]: x = print('This is a x')
This is a x
In [16]: x
In [17]: x = input('Enter a x: ')
Enter a x: x

Он работает для простых операторов, в python 7 их 11 типов . Простые операторы - документация Python 3.6.3

Как насчет составного заявления,

In [18]: m = n**2 + 2*n + 1 if n > 0
SyntaxError: invalid syntax
#or
In [19]: m = n**2 + 2*n + 1, if n > 0
SyntaxError: invalid syntax

Приходит, def чтобы он работал

In [23]: def m(n):
    ...:     if n > 0:
    ...:         return n**2 + 2*n + 1
    ...:
In [24]: m(2)
Out[24]: 9

Тада, проанализируй, m - это имя, n ** 2 + 2 * n + 1 - ценность. : является вариантом '='.
Найдите его, хотя бы для понимания, все начинается с задания и все является заданием.

Теперь вернемся к lambda, у нас есть функция с именем 'm'

Пытаться:

In [28]: m = m(3)
In [29]: m
Out[29]: 16

Здесь два имени «м», функция m уже имеет имя, дублируется.

Это форматирование примерно так:

In [27]: m = def m(n):
    ...:         if n > 0:
    ...:             return n**2 + 2*n + 1
    SyntaxError: invalid syntax

Это неразумная стратегия, поэтому отчеты об ошибках

Мы должны удалить один из них, установить функцию без имени.

m = lambda n:n**2 + 2*n + 1

Это называется "анонимная функция"

В заключение,

  1. lambda во встроенной функции, которая позволяет вам писать функцию в одну прямую линию, как это делается в математике
  2. lambda анонимно

Надеюсь это поможет.

На вопрос дан полный ответ, не хочу вдаваться в подробности. Хочу поделиться использованием при написании числовых вычислений в ржавчине.

Вот пример лямбды (анонимной функции)

let f = |x: f32| -> f32 { x * x - 2.0 };
let df = |x: f32| -> f32 { 2.0 * x };

Когда я писал модуль метода Ньютона – Рафсона, он использовался как производная первого и второго порядка. (Если вы хотите узнать, что такое метод Ньютона – Рафсона, посетите " https://en.wikipedia.org/wiki/Newton%27s_method ".

Результат как следующий

println!("f={:.6}      df={:.6}", f(10.0), df(10.0))

f=98.000000       df=20.000000

Представьте, что у вас есть ресторан с возможностью доставки, и у вас есть заказ, который нужно сделать менее чем за 30 минут. Дело в том, что клиентов обычно не волнует, отправляете ли вы еду на велосипеде с автомобилем или босиком, если вы сохраняете еду теплой и связанной. Итак, давайте конвертируем эту идиому в Javascript с анонимными и определенными транспортными функциями.

Ниже мы определили способ доставки, или мы определяем имя функции:

// ES5 
var food = function withBike(kebap, coke) {
return (kebap + coke); 
};

Что, если бы мы использовали стрелочные / лямбда-функции для выполнения этой передачи:

// ES6    
const food = (kebap, coke) => { return kebap + coke };

Видите ли, для клиента нет разницы и нет времени тратить время на размышления о том, как отправить еду. Просто отправь это.

Кстати, я не рекомендую шашлык с кокаином, поэтому верхние коды выдадут вам ошибки. Повеселись.

A Lambda Functionили a Small Anonymous Function- это автономный блок функциональности, который можно передавать и использовать в вашем коде. Lambda имеет разные имена в разных языках программирования - Lambdaв Python и Kotlin , Closureв Swift или Blockв C и Objective-C . Хотя значение лямбды для этих языков очень похоже, иногда оно имеет небольшие различия.

Давайте посмотрим, как Lambda (Closure) работает в Swift 4.2 с методом sorted () - от обычной функции до кратчайшего выражения:

let coffee: [String] = ["Cappuccino", "Espresso", "Latte", "Ristretto"]

1. Нормальное функционирование

func backward(_ n1: String, _ n2: String) -> Bool {
    return n1 > n2
}
var reverseOrder = coffee.sorted(by: backward)


// RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"]

2. Замыкающее выражение

reverseOrder = coffee.sorted(by: { (n1: String, n2: String) -> Bool in
    return n1 > n2
})

3. Выражение встроенного замыкания

reverseOrder = coffee.sorted(by: { (n1: String, n2: String) -> Bool in return n1 > n2 } )

4. Вывод типа из контекста

reverseOrder = coffee.sorted(by: { n1, n2 in return n1 > n2 } )

5. Неявные возвраты из замыканий с одним выражением

reverseOrder = coffee.sorted(by: { n1, n2 in n1 > n2 } )

6. Сокращенные имена аргументов

reverseOrder = coffee.sorted(by: { $0 > $1 } )

// $0 and $1 are closure’s first and second String arguments.

7. Операторские методы

reverseOrder = coffee.sorted(by: >)

// RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"]

Надеюсь это поможет.

Лямбда объяснил всем:

Лямбда - анонимная функция. Это означает, что лямбда - это объект функции в Python, который раньше не требовал ссылки. Давайте рассмотрим этот фрагмент кода здесь:

def name_of_func():
    #command/instruction
    print('hello')

print(type(name_of_func))   #the name of the function is a reference
                            #the reference contains a function Object with command/instruction

Чтобы подтвердить свое предположение, я распечатываю тип name_of_func, который нам возвращает:

<class 'function'>

Функция должна иметь интерфейс, но доцент интерфейса должен что-то содержать. Что это значит? Давайте посмотрим немного ближе к нашей функции, и мы можем заметить, что в названии функций есть еще некоторые детали, которые нам нужно объяснить, чтобы понять, что такое функция.

Обычная функция будет определена с синтаксисом «def» , затем мы вводим имя и устанавливаем интерфейс с помощью «()» и заканчиваем наше определение синтаксисом «:» . Теперь входим в тело функции с нашими инструкциями / командами.

Итак, давайте рассмотрим этот фрагмент кода здесь:

def print_my_argument(x):
    print(x)


print_my_argument('Hello')

В этом случае мы запускаем нашу функцию с именем «print_my_argument» и передаем параметр / аргумент через интерфейс. Результатом будет:

Hello

Итак, теперь, когда мы знаем, что такое функция и как работает архитектура функции, мы можем взглянуть на анонимную функцию. Давайте рассмотрим этот фрагмент кода здесь:

def name_of_func():
    print('Hello')



lambda: print('Hello')

эти функциональные объекты почти одинаковы, за исключением того факта, что верхняя, обычная функция имеет имя, а другая функция является анонимной. Давайте подробнее рассмотрим нашу анонимную функцию, чтобы понять, как ее использовать.

Итак, давайте рассмотрим этот фрагмент кода здесь:

def delete_last_char(arg1=None):
    print(arg1[:-1])

string = 'Hello World'
delete_last_char(string)

f = lambda arg1=None: print(arg1[:-1])
f(string)

Итак, что мы сделали в приведенном выше коде, так это снова написали обычную функцию и анонимную функцию. Наша анонимная функция, которую мы присвоили переменной, почти то же самое, что присвоить этой функции имя. В любом случае вывод будет:

Hello Worl
Hello Worl

Чтобы полностью доказать, что лямбда является функциональным объектом, а не просто имитирует функцию, мы запускаем этот фрагмент кода здесь:

string = 'Hello World'
f = lambda arg1=string: print(arg1[:-1])
f()
print(type(f))

и результат будет:

Hello Worl
<class 'function'>

И последнее, но не менее важное: вы должны знать, что каждая функция в Python должна что-то возвращать. Если в теле функции ничего не определено, по умолчанию будет возвращено None. посмотрите на этот фрагмент кода здесь:

def delete_last_char(arg1):
    print(arg1[:-1])

string = 'Hello World'
x = delete_last_char(string)

f = lambda arg1=string: print(arg1[:-1])
x2 = f()

print(x)
print(x2)

Результат будет:

Hello Worl
Hello Worl
None
None

Лямбда-исчисление - это последовательная математическая теория подстановки. В школьной математике можно увидеть, например, в x+y=5 паре с x−y=1 . Наряду со способами манипулирования отдельными уравнениями также можно объединить информацию из этих двух при условии, что подстановки между уравнениями выполняются логически. Лямбда-исчисление кодифицирует правильный способ выполнения этих замен.

Учитывая, что y = x−1 это допустимая перестановка второго уравнения, это: λ y = x−1 означает функцию, заменяющую символы x−1 на символы y . Теперь представьте, что вы применяете его λ y к каждому члену в первом уравнении. Если термин есть, y выполните замену; в противном случае ничего не делать. Если вы сделаете это на бумаге, то увидите, как это λ y сделает первое уравнение разрешимым.

Это ответ без каких-либо компьютерных наук или программирования.

Самый простой пример программирования, который я могу придумать, взят из http://en.wikipedia.org/wiki/Joy_(programming_language)#How_it_works :

вот как квадратная функция может быть определена на императивном языке программирования (C):

int square(int x)
{
    return x * x;
}

Переменная x - это формальный параметр, который заменяется фактическим значением, возводимым в квадрат при вызове функции. На функциональном языке (схеме) была бы определена та же функция:

(define square
  (lambda (x) 
    (* x x)))

Это во многом отличается, но формальный параметр x используется таким же образом.


Добавлено: http://imgur.com/a/XBHub

лямбда

Лямбда-функция может принимать любое количество аргументов, но они содержат только одно выражение. ... Лямбда-функции могут использоваться для возврата функциональных объектов. Синтаксически лямбда-функции ограничены только одним выражением.

Вы можете думать об этом как об анонимной функции - вот еще немного информации: Википедия - Анонимная функция

Это функция, у которой нет имени. Например, в С # вы можете использовать

numberCollection.GetMatchingItems<int>(number => number > 5);

чтобы вернуть числа больше 5.

number => number > 5

здесь лямбда-часть. Он представляет функцию, которая принимает параметр (число) и возвращает логическое значение (число> 5). Метод GetMatchingItems использует эту лямбду для всех элементов в коллекции и возвращает соответствующие элементы.

Лямбда - это тип функции, определенный в строке. Наряду с лямбдой у вас также обычно есть какой-то тип переменной, который может содержать ссылку на функцию, лямбда или что-то еще.

Например, вот фрагмент кода C#, в котором не используется лямбда:

public Int32 Add(Int32 a, Int32 b)
{
    return a + b;
}

public Int32 Sub(Int32 a, Int32 b)
{
    return a - b;
}

public delegate Int32 Op(Int32 a, Int32 b);

public void Calculator(Int32 a, Int32 b, Op op)
{
    Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}

public void Test()
{
    Calculator(10, 23, Add);
    Calculator(10, 23, Sub);
}

Это вызывает Calculator, передавая не только два числа, но и метод, который нужно вызвать внутри Calculator для получения результатов расчета.

В C# 2.0 мы получили анонимные методы, которые сокращают приведенный выше код до:

public delegate Int32 Op(Int32 a, Int32 b);

public void Calculator(Int32 a, Int32 b, Op op)
{
    Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}

public void Test()
{
    Calculator(10, 23, delegate(Int32 a, Int32 b)
    {
        return a + b;
    });
    Calculator(10, 23, delegate(Int32 a, Int32 b)
    {
        return a - b;
    });
}

А затем в C# 3.0 мы получили лямбды, которые сделали код еще короче:

public delegate Int32 Op(Int32 a, Int32 b);

public void Calculator(Int32 a, Int32 b, Op op)
{
    Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}

public void Test()
{
    Calculator(10, 23, (a, b) => a + b);
    Calculator(10, 23, (a, b) => a - b);
}

Слегка упрощено: лямбда-функция - это функция, которую можно передать другим функциям и получить доступ к ее логике.

В C# лямбда-синтаксис часто компилируется в простые методы так же, как анонимные делегаты, но его также можно разбить и прочитать его логику.

Например (в C# 3):

LinqToSqlContext.Where( 
    row => row.FieldName > 15 );

LinqToSql может читать эту функцию (x> 15) и преобразовывать ее в фактический SQL для выполнения с использованием деревьев выражений.

Утверждение выше становится:

select ... from [tablename] 
where [FieldName] > 15      --this line was 'read' from the lambda function

Это отличается от обычных методов или анонимных делегатов (которые на самом деле являются просто магией компилятора), потому что они не могут быть прочитаны .

Не все методы в C#, использующие лямбда-синтаксис, могут быть скомпилированы в деревья выражений (т.е. фактические лямбда-функции). Например:

LinqToSqlContext.Where( 
    row => SomeComplexCheck( row.FieldName ) );

Теперь дерево выражения не может быть прочитано - SomeComplexCheck не может быть разбит. Оператор SQL будет выполняться без where, и каждая строка данных будет пропущена SomeComplexCheck .

Не следует путать лямбда-функции с анонимными методами. Например:

LinqToSqlContext.Where( 
    delegate ( DataRow row ) { 
        return row.FieldName > 15; 
    } );

У этого также есть «встроенная» функция, но на этот раз это просто магия компилятора - компилятор C# разделит ее на новый метод экземпляра с автоматически сгенерированным именем.

Анонимные методы не могут быть прочитаны, и поэтому логика не может быть преобразована, как для лямбда-функций.

Это относится к лямбда-исчислению , которое представляет собой формальную систему, в которой есть только лямбда-выражения, которые представляют функцию, которая принимает функцию в качестве единственного аргумента и возвращает функцию. Все функции в лямбда - исчислении этого типа, то есть λ : λ → λ .

Lisp использовал лямбда-концепцию для обозначения своих анонимных функциональных литералов. Эта лямбда представляет функцию, которая принимает два аргумента, x и y, и возвращает их продукт:

(lambda (x y) (* x y)) 

Его можно применить в строке следующим образом (оценивается до 50 ):

((lambda (x y) (* x y)) 5 10)

Мне трудно сосредоточиться на лямбда-выражениях, потому что я работаю в Visual FoxPro, в котором есть подстановка макросов и функции ExecScript {} и Evaluate (), которые, похоже, служат примерно той же цели.

? Calculator(10, 23, "a + b")
? Calculator(10, 23, "a - b");

FUNCTION Calculator(a, b, op)
RETURN Evaluate(op)

Несомненным преимуществом использования формальных лямбда-выражений является (я полагаю) проверка во время компиляции: Fox не узнает, если вы напечатаете текстовую строку выше, пока не попытается ее запустить.

Это также полезно для кода, управляемого данными: вы можете хранить целые процедуры в мемо-полях в базе данных, а затем просто оценивать их во время выполнения. Это позволяет вам настраивать часть приложения, фактически не имея доступа к источнику. (Но это совсем другая тема.)

Название «лямбда» - просто исторический артефакт. Все, о чем мы говорим, это выражение, значение которого является функцией.

Простой пример (с использованием Scala для следующей строки):

args.foreach(arg => println(arg))

где аргумент foreach метода является выражением анонимной функции. Вышеупомянутая строка более или менее похожа на написание чего-то вроде этого (не совсем реальный код, но вы поймете идею):

void printThat(Object that) {
  println(that)
}
...
args.foreach(printThat)

за исключением того, что вам не нужно беспокоиться о:

  1. Объявление функции в другом месте (и необходимость искать ее при повторном просмотре кода позже).
  2. Называя то, что вы используете только один раз.

Когда вы привыкли к значениям функций, обходиться без них кажется такой же глупой, как требовать называть каждое выражение, например:

int tempVar = 2 * a + b
...
println(tempVar)

вместо того, чтобы просто писать выражение там, где оно вам нужно:

println(2 * a + b)

Точные обозначения варьируются от языка к языку; Греческий язык требуется не всегда! ;-)

В Javascript, например, функции рассматриваются как же смешанного типа , как и все остальное ( int, string, float, bool ). Таким образом, вы можете создавать функции на лету, назначать их вещам и вызывать их позже. Это полезно, но не то, чем вы хотите злоупотреблять, иначе вы запутаете всех, кто должен поддерживать ваш код после вас ...

Это код, с которым я играл, чтобы увидеть, насколько глубока эта кроличья нора:

var x = new Object;
x.thingy = new Array();
x.thingy[0] = function(){ return function(){ return function(){ alert('index 0 pressed'); }; }; }
x.thingy[1] = function(){ return function(){ return function(){ alert('index 1 pressed'); }; }; }
x.thingy[2] = function(){ return function(){ return function(){ alert('index 2 pressed'); }; }; }

for(var i=0 ;i<3; i++)
    x.thingy[i]()()();