Jeneratör fonksiyonları fonksiyonel programlamada geçerli mi?


17

Sorular:

  • Jeneratörler fonksiyonel programlama paradigmasını kırıyor mu? Neden ya da neden olmasın?
  • Evetse, jeneratörler fonksiyonel programlamada kullanılabilir ve nasıl?

Aşağıdakileri göz önünde bulundur:

function * downCounter(maxValue) {
  yield maxValue;
  yield * downCounter(maxValue > 0 ? maxValue - 1 : 0);
}

let counter = downCounter(26);
counter.next().value; // 26
counter.next().value; // 25
// ...etc

downCounterYöntem durum bilgisi görüntülenir. Ayrıca downCounter, aynı girişle çağrı yapmak her zaman aynı çıkışla sonuçlanacaktır. Ancak, aynı zamanda arama next()tutarlı sonuçlar üretmez.

Bu örnekte counterbir jeneratör nesnesi olduğu için jeneratörlerin fonksiyonel programlama paradigmasını bozup kırmadığından emin değilim ve bu nedenle çağrı next(), tam olarak aynı olan başka bir jeneratör nesnesiyle aynı sonuçları üretecektir maxValue.

Ayrıca someCollection[3], bir diziyi çağırmak her zaman dördüncü öğeyi döndürür. Benzer şekilde, next()bir jeneratör nesnesine dört kez çağrı yapmak da daima dördüncü elemanı döndürür.

Daha fazla bağlam için, bu sorular bir programlama kata üzerinde çalışırken ortaya atıldı . Soruyu cevaplayan kişi, jeneratörlerin fonksiyonel programlamada kullanılıp kullanılamayacağı ve durumu olup olmadıkları sorusunu gündeme getirdi.


2
Her program devlete sahiptir. Asıl soru, "değişmez durum" olarak yorumladığım işlevsel durum olarak nitelendirilip nitelendirilmediğidir . Bir jeneratörün her çağrıda farklı bir şey döndürmesini sağlamanın tek yolunun değişebilir durumun bir şekilde karışması olduğunu iddia ediyorum.
Robert Harvey

Yanıtlar:


14

Jeneratör fonksiyonları özel değildir. Jeneratör işlevini geri arama tabanlı bir tarzda yeniden yazarak benzer bir mekanizmayı kendimiz uygulayabiliriz:

function downCounter(maxValue) {
  return {
    "value": maxValue,
    "next": function () {
      return downCounter(maxValue > 0 ? maxValue - 1 : 0);
     },
  };
}

let counter = downCounter(26);
counter.value; //=> 26
counter.next().value; //=> 25

Açıkçası, downCounterolduğu kadar saf ve işlevseldir. Burada hiçbir sorun yok.

JavaScript tarafından kullanılan jeneratör protokolü değiştirilebilir bir nesne içerir. Bu gerekli değildir, yukarıdaki koda bakın. Özellikle, değiştirilebilir nesneler referans şeffaflığını kaybettiğimiz anlamına gelir - bir ifadeyi değerine göre değiştirme yeteneği. Benim örnekte, iken counter.next().valueedecek hep üzere değerlendirmek 25bir noktada öyle - bu gerçekleşir ve ne sıklıkta bunu tekrarlamak olursa olsun, bu JS jeneratör ile durum böyle değil 26o zaman, 25ve gerçekten herhangi bir sayı olabilir. Jeneratöre bir referansı başka bir fonksiyona geçirirsek bu sorunludur:

counter.next().value; //=> 25
otherFunction(counter); // does this consume the counter?
counter.next().value; // what will this be? It depends on the otherFunction()

Açık bir şekilde, jeneratörler devlet sahibidir ve bu nedenle “saf” fonksiyonel programlama için uygun değildir. Neyse ki, saf fonksiyonel programlama yapmak zorunda değilsiniz ve bunun yerine pragmatik olabilir. Jeneratörler kodunuzu daha net hale getirirse, bunları kötü bir vicdan olmadan kullanmalısınız. Sonuçta, JavaScript Haskell'den farklı olarak saf işlevsel bir dil değildir.

Bu arada, Haskell'de tembel değerlendirme kullandığından bir liste ve jeneratör döndürmek arasında bir fark yoktur:

downCounter :: Int -> [Int]
downCounter maxValue =
  maxValue : (downCounter (max 0 (maxValue - 1)))
-- invoke as "take n (downCounter 26)" to display n elements
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.