SORU
24 Aralık 2012, PAZARTESİ


'devamı arasındaki fark ne ve bir geri arama?

Devamı hakkında aydınlanma arayışında internette tarama yaptım ve zihin açıklamalar en basiti bu kadar kendim gibi JavaScript programcısı etkilemesi için nasıl almaz. Bu makalelerin çoğu düzeninde kodu ile devamı açıklamak ya da monadlar kullanmak doğrudur.

Sonunda devamı özünü anladım sanırım şimdi bildiğim şey aslında gerçek olup olmadığını bilmek istedim. Eğer doğru olduğunu düşündüğüm şeyi gerçekten doğru değilse, o zaman cehalet ve aydınlanma değil.

Yani, bildiğim şey şu:

Neredeyse tüm dillerde işlevleri açıkça onların arayana değerleri (ve kontrol) dönüş. Örneğin:

var sum = add(2, 3);

alert(sum);

function add(x, y) {
    return x   y;
}

Birinci sınıf fonksiyonları ile bir dil artık kontrolden geçmiş ve açıkça arayan dönmek yerine bir geri dönüş değeri olabilir

add(2, 3, function (sum) {
    alert(sum);
});

function add(x, y, cont) {
    cont(x   y);
}

Böylece bir işlev bir değer yerine başka bir işlev ile devam ediyoruz. Bu nedenle bu işlev ilk olarak bir devamı olarak adlandırılır.

Devamı ve bir geri arama arasında ne fark var?

CEVAP
24 Aralık 2012, PAZARTESİ


Devamı için geri özel bir durum olduğuna inanıyorum. Fonksiyon fonksiyonları herhangi bir sayıda, herhangi bir kaç kez geri olabilir. Örneğin:

var array = [1, 2, 3];

forEach(array, function (element, array, index) {
    array[index] = 2 * element;
});

function forEach(array, callback) {
    var length = array.length;
    for (var i = 0; i < length; i  )
        callback(array[i], array, i);
}

Ancak eğer bir işlev başka bir işlevi, daha sonra ilk bir devamı olarak adlandırılan ikinci işlev yapacağı son şey olarak geri arar. Örneğin:

var array = [1, 2, 3];

forEach(array, function (element, array, index) {
    array[index] = 2 * element;
});

function forEach(array, callback) {
    var length = array.length;

    // This is the last thing forEach does
    // cont is a continuation of forEach
    cont(0);

    function cont(index) {
        if (index < length) {
            callback(array[index], array, index);
            // This is the last thing cont does
            // cont is a continuation of itself
            cont(  index);
        }
    }
}

Eğer bir işlev yaptığı son şey başka bir işlevini çağırırsa o zaman kuyruk arayın deniyor. Düzeni gibi bazı diller kuyruk çağrı iyileştirmeleri gerçekleştirmek. Bu kuyruk çağrısı bir işlev çağrısı tam yükünü anlamına gelir. Bunun yerine basit bir goto arama fonksiyonu yığın çerçevesi kuyruk çağrısı yerini yığın çerçeve ile) olarak uygulanır.

Bonus: Devamı geçirilmesi için stil ilerliyor. Aşağıdaki programı deneyin:

alert(pythagoras(3, 4));

function pythagoras(x, y) {
    return x * x   y * y;
}

Şimdi her işlem (toplama, çarpma, vb. dahil) fonksiyonlar şeklinde yazılmış olurdu o zaman:

alert(pythagoras(3, 4));

function pythagoras(x, y) {
    return add(square(x), square(y));
}

function square(x) {
    return multiply(x, x);
}

function multiply(x, y) {
    return x * y;
}

function add(x, y) {
    return x   y;
}

Eğer herhangi bir değer döndürmek için izin olmasaydık ayrıca o zaman şöyle: devamı için kullanmak zorunda kalacaktık

pythagoras(3, 4, alert);

function pythagoras(x, y, cont) {
    square(x, function (x_squared) {
        square(y, function (y_squared) {
            add(x_squared, y_squared, cont);
        });
    });
}

function square(x, cont) {
    multiply(x, x, cont);
}

function multiply(x, y, cont) {
    cont(x * y);
}

function add(x, y, cont) {
    cont(x   y);
}

Değerleri (ve dolayısıyla çevresinde devamı geçirmeden başvurmak gerekir) geri dönmek için izin verilmez bu stili programlama devamı geçirmeden tarzı denir.

Ancak devamında geçen stili ile iki sorun vardır:

  1. Devamı için etrafa çağrı yığın boyutu artar. Kuyruk aramaları ortadan kaldıran Düzeni gibi bir dil kullanmadığınız sürece yığın alanı dışı risk.
  2. İç içe fonksiyonlar yazmak için bir ağrı.

İlk sorun kolayca devamı uyumsuz çağırarak JavaScript ile çözülebilir. Devamı uyumsuz çağırarak devamı önce işlev denir. Dolayısıyla çağrı boyutunu arttırmaz yığını:

Function.prototype.async = async;

pythagoras.async(3, 4, alert);

function pythagoras(x, y, cont) {
    square.async(x, function (x_squared) {
        square.async(y, function (y_squared) {
            add.async(x_squared, y_squared, cont);
        });
    });
}

function square(x, cont) {
    multiply.async(x, x, cont);
}

function multiply(x, y, cont) {
    cont.async(x * y);
}

function add(x, y, cont) {
    cont.async(x   y);
}

function async() {
    setTimeout.bind(null, this, 0).apply(null, arguments);
}

İkinci sorun, genellikle sık sık callcc olarak kısaltılmış olan bir fonksiyon call-with-current-continuation adı kullanılarak çözüldü. Ne yazık ki callcc JavaScript tam olarak uygulanabilir değil, ama kullanmak vakalar: çoğu için yedek bir fonksiyon yazabiliriz

pythagoras(3, 4, alert);

function pythagoras(x, y, cont) {
    var x_squared = callcc(square.bind(null, x));
    var y_squared = callcc(square.bind(null, y));
    add(x_squared, y_squared, cont);
}

function square(x, cont) {
    multiply(x, x, cont);
}

function multiply(x, y, cont) {
    cont(x * y);
}

function add(x, y, cont) {
    cont(x   y);
}

function callcc(f) {
    var cc = function (x) {
        cc = x;
    };

    f(cc);

    return cc;
}

callcc işlev f alır current-continuation (cc olarak kısaltılmış) için geçerlidir. current-continuation 32 ** çağrısının işlevi vücudun geri kalanı da sona erecek olan devamı bir fonksiyonudur.

33**: işlev gövdesi olarak düşünün

var x_squared = callcc(square.bind(null, x));
var y_squared = callcc(square.bind(null, y));
add(x_squared, y_squared, cont);

current-continuation ikinci callcc:

function cc(y_squared) {
    add(x_squared, y_squared, cont);
}

Benzer şekilde callcc ilk current-continuation:

function cc(x_squared) {
    var y_squared = callcc(square.bind(null, y));
    add(x_squared, y_squared, cont);
}

İlk current-continuation beri callcc devamı için stil geçen dönüştürülmüş olmalıdır. callcc başka bir içerir:

function cc(x_squared) {
    square(y, function cc(y_squared) {
        add(x_squared, y_squared, cont);
    });
}

Aslında callcc mantıksal olarak tüm fonksiyon vücuttan başladığımız şeyi geri çevirir (ve bu isimsiz işlevler 46 ** adını verir):

square(x, function cc(x_squared) {
    square(y, function cc(y_squared) {
        add(x_squared, y_squared, cont);
    });
});

Yine JavaScript callcc uygulamak mümkün değil ama aşağıdaki gibi devam JavaScript tarzı geçen uygulayabilirsiniz

Function.prototype.async = async;

pythagoras.async(3, 4, alert);

function pythagoras(x, y, cont) {
    callcc.async(square.bind(null, x), function cc(x_squared) {
        callcc.async(square.bind(null, y), function cc(y_squared) {
            add.async(x_squared, y_squared, cont);
        });
    });
}

function square(x, cont) {
    multiply.async(x, x, cont);
}

function multiply(x, y, cont) {
    cont.async(x * y);
}

function add(x, y, cont) {
    cont.async(x   y);
}

function async() {
    setTimeout.bind(null, this, 0).apply(null, arguments);
}

function callcc(f, cc) {
    f.async(cc);
}

callcc karmaşık kontrol uygulamak için kullanılabilir işlevi try-catch blokları, coroutines, jeneratörler gibi yapılar, fibers, vb akışı.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Ben Schoon

    Ben Schoon

    23 Kasım 2012
  • Jason Parker

    Jason Parker

    14 Aralık 2009
  • parlophone

    parlophone

    28 ŞUBAT 2006