Neden ciltleme çoğu dilde yerel bir özellik değildir?


11

Bir değişkeni başka bir değişkene veya ifadeye bağlayan IMHO, matematikte çok yaygın bir senaryodur. Aslında, başlangıçta, birçok öğrenci atama operatörünün (=) bir tür bağlayıcı olduğunu düşünmektedir. Ancak dillerin çoğunda ciltleme yerel bir özellik olarak desteklenmez. C # gibi bazı dillerde, bazı durumlarda yerine getirilmiş bazı durumlarda ciltleme desteklenir.

Ancak bunu yerel bir özellik olarak uygulayan IMHO, aşağıdaki kodu değiştirmek kadar basitti.

int a,b,sum;
sum := a + b;
a = 10;
b = 20;
a++;

buna-

int a,b,sum;
a = 10;
sum = a + b;
b = 20;
sum = a + b;
a++;
sum = a + b;

Sağdaki ifadede yer alan değişkenin değerlerini değiştiren her komuttan sonra ciltleme komutunu atamalar olarak yerleştirmek anlamına gelir. Bundan sonra, gereksiz talimatları (veya derlemeden sonra montajda optimizasyon) kırpacaktır.

Peki, neden çoğu dilde yerel olarak desteklenmiyor. Özellikle C ailesinde mi?

Güncelleme:

Farklı görüşlerden, bu önerilen "bağlayıcı" kelimeyi daha kesin olarak tanımlamam gerektiğini düşünüyorum.

  • Bu tek yönlü bağlanmadır. Yalnızca toplam a + b'ye bağlanır, tersi de geçerlidir.
  • Bağlamanın kapsamı yereldir.
  • Bağlama kurulduktan sonra değiştirilemez. Yani, toplam a + b'ye bağlandığında toplam her zaman a + b olacaktır.

Umarım fikir şimdi daha açıktır.

Güncelleme 2:

Sadece bu P # özelliğini istedim . Umarım gelecekte orada olur.


14
Muhtemelen bu özelliği C'ye eklemeye çalışan herhangi bir derleyici geliştiricisi avlandı ve vuruldu.
Pete Wilson

Ben iki yönlü değil, tek yönlü (sağdan sola) ciltleme hakkında konuşuyorum. Bağlama her zaman yalnızca bir değişkeni etkiler.
Gulshan

2
Değeri ne olursa olsun, bu tür bir programatik bakış açısı artıyor: reaktif programlama. Açıkladığınız şey, esasen steroidler üzerinde veri bağlayan (veya reaktif programlama) olan Excel gibi elektronik tablo programları tarafından da somutlaştırılmıştır.
Mike Rosenblum

11
Bu "en" programlama dilleri bir özelliği olmayabilir ama olduğu bir özelliği en popüler programlama dili: Excel.
Jörg W Mittag

2
İfade ağaçları sayesinde, bu C # 'da zaten mümkündür. Ben dün bu konuda blogged: happynomad121.blogspot.com/2013/01/...
HappyNomad

Yanıtlar:


9

Programlamayı matematikle karıştırıyorsunuz. Birçok fikir ödünç alıp programlama için kullanılabilecek ve kullanılabilecek bir şeye dönüştürmesine rağmen fonksiyonel programlama bile tamamen matematik değildir. Zorunlu programlama (C'den ilham alan çoğu dili içeren, JavaScript'in dikkate değer istisnaları ve C # 'a daha yeni ekler içeren) matematikle neredeyse hiçbir ilgisi yoktur, bu yüzden bu değişkenler neden matematikteki değişkenler gibi davranmalı?

Bunun her zaman istediğiniz şey olmadığını düşünmelisiniz. Pek çok insan, döngülerde oluşturulan kapaklardan ısırılır, çünkü kapaklar bir noktada değerinin bir kopyasını değil değişkeni tutar, yani for (i = 0; i < 10; i++) { var f = function() { return i; }; /* store f */ }geri dönen on kapak oluşturur 9. Bu nedenle, her iki yolu da desteklemeniz gerekir. Bu, "karmaşıklık bütçesinin" iki katı maliyet ve başka bir operatör anlamına gelir. Muhtemelen, bunu kullanan kod ile bunu kullanmayan kod arasındaki yetersizlikler, tip sistemi yeterince karmaşık olmadığı sürece (daha karmaşık!).

Ayrıca, bunu etkili bir şekilde uygulamak çok zordur. Saf uygulama, her ödeve sabit bir ek yük getirir ve bu da zorunlu programlarda hızlı bir şekilde toplanabilir. Diğer uygulamalar, değişken okunana kadar güncellemeleri geciktirebilir, ancak bu daha karmaşıktır ve değişken bir daha asla okunmasa bile ek yükü vardır. Yeterince akıllı bir derleyici her ikisini de optimize edebilir, ancak yeterince akıllı derleyiciler nadirdir ve oluşturmak için çok çaba sarf eder (örneğin, değişkenlerin geniş kapsamı ve çoklu iş parçacığı devreye girdiğinde her zaman örnekte olduğu kadar basit olmadığını unutmayın!).

Reaktif programlamanın temel olarak bununla ilgili olduğunu (anlayabildiğim kadarıyla) unutmayın, bu yüzden var. Geleneksel programlama dillerinde yaygın değildir. Ve bahse girerim, önceki paragrafta listelediğim bazı uygulama problemleri çözüldü.


Sanırım 3 puanınız var- 1) Bu tarz programlama zorunlu değildir. Bugünlerde dillerin çoğu bazı paradigmalarla sınırlı değil. Bunun bu paradigma tarzının dışında olduğunu düşünmüyorum iyi bir mantık. 2) Karmaşıklık. Çok daha karmaşık şeylerin zaten desteklendiğini gösterdiniz. Neden olmasın? Neredeyse hiç faydası olmayan operatörlerin desteklendiğini biliyorum. Ve bu tamamen yeni bir özellik. Peki uyumluluk sorunu nasıl olabilir. Bir şeyi değiştirmiyorum ya da silmiyorum. 3) Zor Uygulama. Bugünkü derleyiciler bunu optimize etme yeteneğine sahip olduğunu düşünüyorum.
Gulshan

1
@Gulshan: (1) Hiçbir programlama paradigması matematik değildir. FP yakındır, ancak FP nispeten nadirdir ve değişken değişkenlere sahip saf olmayan FP dilleri de bu değişkenleri matematiktenmiş gibi ele almaz. Bunun var olduğu bir paradigma reaktif programlamadır, ancak reaktif programlama bilinmemekte veya yaygın olarak kullanılmaktadır (geleneksel programlama dillerinde). (2) Her şeyin bir karmaşıklık maliyeti ve bir değeri vardır. Bu yüzden ben eklemek istiyorum ilk şey değil, birkaç etki dışında oldukça yüksek maliyeti ve IMHO nispeten az değeri vardır benim , spesifik olarak bu etki hedeflenen sürece dili.

Kutumuzda neden bir araç daha yok? Bir araç orada olduğunda, insanlar onu kullanacaktır. Bir soru. C veya C ++ gibi bir dil bu özelliği uygulamak ve fikrinizi sormak istiyorsa, "Verme. Çünkü sizin için çok zor olacak ve insanlar bununla uğraşacaklar" der misiniz?
Gulshan

@Gulshan: (3) ile ilgili olarak: Her zaman (nadiren söylememek) örneğinizdeki kadar kolay değildir. Global kapsama girin ve aniden bağlantı zamanı optimizasyonlarına ihtiyacınız var. Ardından dinamik bağlantı ekleyin ve derleme sırasında hiçbir şey yapamazsınız. Bunu yapmak için çok akıllı bir derleyiciye ve JIT dahil çok akıllı bir çalışma süresine ihtiyacınız var. Ayrıca, önemsiz olmayan her programdaki ödev miktarını da göz önünde bulundurun. Ne siz ne de ben bu bileşenleri yazamıyoruz. Bu konuyla ilgilenebilen ve ilgilenen en az birkaç kişi vardır. Ve yapacak daha iyi şeyleri olabilir.

@Gulshan: Onlardan inanılmaz derecede karmaşık C ++ 'a zaten özellik eklememelerini isterdim, ya da sistem programlamasının ötesinde şeyler için C'yi denememelerini isterdim (bu çok yararlı olan alanlardan biri değil) ). Bunun dışında, heyecan verici yeni özellikler için varım, ancak sadece karmaşıklık bütçesinin yeterli olması (birçok dil her zaman onlarınkini tükettiğinde) ve özellik dilin yapması amaçlanan şey için yararlı olduğunda - daha önce de söylediğim gibi, bunun yararlı olduğu yalnızca birkaç alan adıdır.

3

Çoğu programlama modeline çok iyi uymuyor. Tek bir atama yaparak yüzlerce veya binlerce değişkenin ve nesne alanının değerini yok edebileceği, bir mesafeden tamamen kontrolsüz bir eylemi temsil edecektir.


Sonra bir kural koymanızı öneririm, yani bağlı değişken yani sol taraf başka bir yolla değiştirilmez. Ve bahsettiğim şey, iki yönlü değil, sadece tek yönlü bağlayıcıdır. Sorumu takip ederseniz görebilirsiniz. Böylece, başka bir değişken etkilenmeyecektir.
Gulshan

Önemli değil. Eğer yazma Her zaman aya b, onun her yerde üzerindeki etkisini dikkate almak gerekir sumkullanılır ve okumak her yerde sumsen dikkate almak gerekir ave byapıyoruz. Önemsiz durumlar için, özellikle bağlı gerçek ifade sumçalışma zamanında değişebiliyorsa , bu karmaşıklaşabilir .
jprete

Bağlama yapıldıktan sonra bağlama ifadesinin değiştirilemeyeceği kuralını öneririm. Atama bile imkansız olacaktır. Bir ifadeye bağlandığında yarı sabit gibi olacaktır. Bu, toplam a + b'ye bağlandıktan sonra, programın geri kalanı boyunca her zaman + b olacaktır.
Gulshan

3

Biliyorsunuz, reaktif programlamanın bir Web2.0 ortamında havalı olabileceğini düşündüğüm bu sersemletici bağırsak hissim var. Neden duygu? Peki, çoğunlukla tablo hücresi onClick olaylarına yanıt olarak sürekli değişen bir tablo olan bu bir sayfa var. Hücre tıklamaları genellikle bir col veya satırdaki tüm hücrelerin sınıfını değiştirmek anlamına gelir; ve bu, ilgili diğer hücreleri bulmak için getRefToDiv () ve benzerlerinin sonsuz döngüleri anlamına gelir.

IOW, yazdığım ~ 3000 JavaScript satırının çoğu, nesneleri bulmaktan başka bir şey yapmıyor. Belki reaktif programlama tüm bunları küçük bir maliyetle yapabilir; ve kod satırlarında büyük bir azalma.

Siz bu konuda ne düşünüyorsunuz? Evet, masamın elektronik tablo benzeri birçok özelliği olduğunu fark ediyorum.


3

Ben açıklamak ne elektronik tablo denir düşünüyorum:

A1=5
B1=A1+1
A1=6

... sonra B1iadeleri değerlendirmek 7.

DÜZENLE

C dili bazen "portatif montaj" olarak adlandırılır. Bu zorunlu bir dildir, e-tablolar vb. Bildirimsel dillerdir. Değiştiğinde yeniden değerlendirmeyi söylemek B1=A1+1ve beklemek kesinlikle beyan edicidir. Bildirici diller (işlevsel dillerinin bir alt küme olduğu) genellikle daha yüksek düzeyli diller olarak kabul edilir, çünkü donanımın çalışma biçiminden daha uzaktırlar.B1A1

İlgili bir notta, merdiven mantığı gibi otomasyon dilleri tipik olarak bildiricidir. Bu output A = input B OR input Cifadeyi sürekli olarak yeniden değerlendireceğini ve Ane zaman Bya da Cdeğiştiğinde değişebileceğini söyleyen bir mantık basamağı yazarsanız . İşlev Bloğu Diyagramı (Simulink kullandıysanız aşina olabileceğiniz) gibi diğer otomasyon dilleri de bildirim niteliğindedir ve sürekli olarak yürütülür.

Bazı (gömülü) otomasyon ekipmanı C'de programlanır ve gerçek zamanlı bir sistemse, muhtemelen mantığın merdiven mantığının nasıl çalıştığına benzer şekilde tekrar tekrar yürüten sonsuz bir döngüye sahiptir. Bu durumda, ana döngünüzün içine şunları yazabilirsiniz:

A = B || C;

... ve her zaman yürüttüğü için, bildirimsel hale geliyor. Asürekli olarak yeniden değerlendirilecektir.


3

C, C ++, Amaç-C:

Bloklar , aradığınız ciltleme özelliğini sağlar.

Örneğinizde:

toplam: = a + b;

sumifadeyi , var olan ve değişkenler a + bolduğu bir bağlamda ayarlıyorsunuz . Tam olarak, Apple uzantılarıyla C, C ++ veya Objective-C'de bir "blok" (aka kapatma, aka lambda ifadesi ) yapabilirsiniz:ab

__block int a = 0, b = 0;           // declare a and b
int (^sum)(void);                   // declare sum
sum = ^(void){return a + b;};       // sum := a + b

Bu sum, a ve b'nin toplamını döndüren bir bloğa ayarlanır . __blockDepolama sınıfı belirteci olduğunu gösterir ave bdeğişebilir. Yukarıdakiler göz önüne alındığında, aşağıdaki kodu çalıştırabiliriz:

printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
a = 10;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
b = 32;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());
a++;
printf("a=%d\t b=%d\t sum=%d\n", a, b, sum());

ve çıktıyı alın:

a=0      b=0     sum=0
a=10     b=0     sum=10
a=10     b=32    sum=42
a=11     b=32    sum=43

Bir blok kullanma ve önerdiğiniz "bağlama" arasındaki tek fark boş parantez çiftidir sum(). Arasındaki fark sumve sum()bir ifade ve ifade sonuç arasındaki farktır. İşlevlerde olduğu gibi parantezlerin de boş olması gerekmediğine dikkat edin - bloklar da işlevler gibi parametreleri alabilir.


2

C ++

Genel olarak güncellendi. Dönüş ve giriş türlerinde parametrelendirildi. Parametrelendirilmiş türleri tatmin eden herhangi bir ikili işlemi sağlayabilir. Kod talep üzerine sonucu hesaplar. Eğer sonuçtan kurtulabiliyorsa sonuçları yeniden hesaplamamaya çalışır. Bu istenmezse bunu çıkarın (yan etkiler nedeniyle, içerdiği nesneler büyük, çünkü her ne olursa olsun).

#include <iostream>

template <class R, class A, class B>
class Binding {
public:
    typedef R (*BinOp)(A, B);
    Binding (A &x, B &y, BinOp op)
        : op(op)
        , rx(x)
        , ry(y)
        , useCache(false)
    {}
    R value () const {
        if (useCache && x == rx && y == ry) {
            return cache;
        }
        x = rx;
        y = ry;
        cache = op(x, y);
        useCache = true;
        return cache;
    }
    operator R () const {
        return value();
    }
private:
    BinOp op;
    A &rx;
    B &ry;
    mutable A x;
    mutable B y;
    mutable R cache;
    mutable bool useCache;
};

int add (int x, int y) {
    return x + y;
}

int main () {
    int x = 1;
    int y = 2;
    Binding<int, int, int> z(x, y, add);
    x += 55;
    y *= x;
    std::cout << (int)z;
    return 0;
}

Soruyu cevaplamasa da, sunduğunuz fikri beğendim. Daha genel bir sürüm olabilir mi?
Gulshan

@Gulshan: Güncellendi
Thomas Eding
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.