Как разные языки программирования используют замыкания? - PullRequest
3 голосов
/ 14 сентября 2009

Насколько мне известно, в сочетании со знанием других, среди основных языков

  • Цель C
  • C #
  • VB.net
  • Java
  • Python
  • рубин
  • Javascript
  • 1020 * Лисп *
  • Perl

имеет замыкания и анонимные функции. Обычный C / C ++ не имеет ни одного из них.

Есть ли у замыканий в этих языках одинаковая семантика? Насколько они важны для повседневного программирования?

Некоторые предыстории: Я читал о новых дополнениях к Цель C, которые предназначены для Apple Grand Central Dispatch, и подумал, что мне следует узнать, действительно ли существует только один или различные способы введения блочных структур в язык.

Ответы [ 4 ]

5 голосов
/ 14 сентября 2009

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

Процесс компиляции .NET-языков (VB / C #) может показать вам, как вообще можно представить замыкания:

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

Некоторые примечания о важности замыканий:

  • .NET: Не так много явного использования замыканий. Анонимные функции иногда используются для событий и функционального представления данных. Основное использование - это (внутреннее) представление LINQ-запросов.

  • Python: Плохая поддержка анонимных функций - только lambda vars: expr - синтаксис.

  • Javascript: весь синтаксис функции - не что иное, как синтаксический сахар вокруг анонимных функций и замыканий!

    function f(x) { return x + 1; }
    

    равно

    var f = function(x) { return x + 1; }
    
  • Ruby: Интенсивное использование замыканий: большинство структур программных потоков используют их. См

    array.each do |x|
       # code
    end
    

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

    Array.Each(x => {
        // Code
    })
    

Обычно замыкание выглядит примерно так:

# Enclose `i` - Return function pointer
def counter():
    i = 0
    def incr():
        i += 1
        print(i)
    return incr

c = counter()
c() # -> 1
c() # -> 2
c() # -> 3

Все языки (кроме Java - у вас есть анонимные классы, а не функции!), Которые вы перечислили, допускают подобные вещи.

3 голосов
/ 14 сентября 2009

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

Начиная с день 1 v1.1, однако, Java поддерживала ту же функциональность, но вместо смешивания парадигм (функциональных и ОО) они допускали существование анонимных внутренних классов, которые в значительной степени служат для того же цель. Так как они не замыкания, а классы, вы должны ввести еще несколько символов.

Так, например, чтобы иметь Timer, который получает TimerTask в качестве блока для выполнения, вы должны написать:

 Timer timer = new Timer();

 timer.schedule( new TimerTask() {  // this is like the code block. 
     public void run() {
          System.out.println("Hey!");
     }
 },0);

Как видите, TimerTask () {... "- это определение для анонимного внутреннего класса. Этот экземпляр также может быть присвоен переменной a, переданной в качестве аргумента.

TimerTask task = new TimerTask() {
     public void run() {
     }
 };


....
timer.schedule( task , 0 ) ;

У вас могут быть такие типы конструкций, но они не являются замыканиями.

Затворы все еще обсуждаются и будут добавлены в язык программирования Java.

Вот интересный разговор Джошуа Блоха: "Спор о замыканиях"

Вот статья о «Принципы развития языка Java»

2 голосов
/ 15 сентября 2009

Основное преднамеренное различие в семантике между основными языками состоит в том, разрешать ли изменения переменных, захваченных замыканием. Java и Python говорят «нет», другие языки говорят «да» (ну, я не знаю Objective C, но остальные знают). Преимущество возможности изменять переменные состоит в том, что вы можете писать код следующим образом:

public static Func<int,int> adderGen(int start) {
    return (delegate (int i) {      // <-- start is captured by the closure
                start += i;         // <-- and modified each time it's called
                return start;
            });
}
// later ...
var counter = adderGen(0);
Console.WriteLine(counter(1)); // <-- prints 1
Console.WriteLine(counter(1)); // <-- prints 2
// :
// :

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

var adders = new List<Func<int,int>>();

for(int start = 0; start < 5; start++) {
    adders.Add(delegate (int i) {
        start += i;
        return start;
    });
}

Console.WriteLine(adders[0](1)); // <-- prints 6, not 1
Console.WriteLine(adders[4](1)); // <-- prints 7, not 5

Мало того, что start является общим для всех 5 замыканий, повторное start++ дает ему значение 5 в конце цикла for. В языке смешанной парадигмы мое мнение заключается в том, что Java и Python имеют правильную идею - если вы хотите изменить захваченные переменные, вам лучше вместо этого создать класс, который делает захват Процесс явный, когда вы передаете их конструктору, например. Мне нравится хранить замыкания для функционального программирования.

Кстати, у Perl тоже есть замыкания.

0 голосов
/ 14 сентября 2009

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

Были предложения о добавлении замыканий в язык в следующей версии Java, но ни одно из них не было включено в список официальных изменений.

...