(Fonksiyonel) reaktif programlama nedir?


1148

Reaktif programlama hakkındaki Wikipedia makalesini okudum . Ayrıca fonksiyonel reaktif programlama hakkındaki küçük makaleyi de okudum . Açıklamalar oldukça soyut.

  1. Fonksiyonel reaktif programlama (FRP) pratikte ne anlama geliyor?
  2. Reaktif programlama (reaktif olmayan programlamanın aksine) nelerden oluşur?

Geçmişim zorunlu / OO dillerinde, bu yüzden bu paradigma ile ilgili bir açıklama takdir edilecektir.


159
Burada aktif hayal gücü ve iyi hikaye anlatımı becerileri olan bir adam her şeyi üstleniyor. paulstovell.com/reactive-programming
melaos

39
Birileri gerçekten burada tüm otodidaktlar için "Aptallar için Fonksiyonel Reaktif Programlama" yazmalıdır. Bulduğum her kaynak, Elm bile, son beş yıl içinde CS'de bir Master aldığınız varsayılıyor. FRP hakkında bilgili olanlar, konuyu saf bakış açısından görme yeteneğini, öğretim, eğitim ve evangelizasyon için kritik bir şey olarak tamamen kaybetmiş gibi görünüyor.
TechZen

26
Başka bir mükemmel FRP tanıtımı: Reaktif Programlamaya giriş meslektaşım André
kaçırıldın

5
Gördüğüm en iyi örneklerden biri, Örnek tabanlı: gist.github.com/staltz/868e7e9bc2a7b8c1f754
Razmig

2
Elektronik tablo benzetmesini ilk kaba bir izlenim olarak çok yararlı buluyorum (bkz. Bob'un yanıtı: stackoverflow.com/a/1033066/1593924 ). Bir elektronik tablo hücresi diğer hücrelerdeki değişikliklere tepki verir (çeker), ancak başkalarına ulaşmaz ve başkalarını değiştirmez (zorlamaz). Sonuç olarak, bir hücreyi ve bir milyon kişiyi kendi ekranlarını 'bağımsız olarak' güncelleyebilirsiniz.
Jon Coombs

Yanıtlar:


931

Eğer FRP hakkında bir fikir edinmek istiyorsanız , animasyonlu resimlere sahip olan 1998'den itibaren eski Fran öğretici ile başlayabilirsiniz . Makaleler için, Fonksiyonel Reaktif Animasyon ile başlayın ve ardından ana sayfamdaki yayınlar linkine ve Haskell wiki'sindeki FRP linkine bakınız .

Şahsen, FRP'nin nasıl uygulanabileceğini ele almadan önce ne anlama geldiğini düşünmeyi seviyorum . (Spesifikasyonu olmayan kod, sorusuz bir cevaptır ve bu nedenle de "yanlış bile değildir"). Bu yüzden, Thomas K'nin başka bir cevapta yaptığı gibi (grafikler, düğümler, kenarlar, ateşleme, yürütme, vb). Birçok olası uygulama tarzları vardır, ama hiçbir uygulama CTP Ne diyor olduğunu .

Laurence G'nin FRP'nin "zaman içinde bir değeri temsil eden veri türleri" ile ilgili basit açıklamasıyla yankılanıyorum. Geleneksel zorunlu programlama bu dinamik değerleri sadece dolaylı olarak durum ve mutasyonlar yoluyla yakalar. Tarihin (geçmiş, şimdiki zaman, gelecek) birinci sınıf temsili yoktur. Dahası, zorunlu olarak paradigma zamansal olarak ayrık olduğundan , sadece ayrı ayrı gelişen değerler (dolaylı olarak) yakalanabilir. Buna karşılık, FRP bu gelişen değerleri doğrudan yakalar ve sürekli gelişen değerlerle hiçbir zorluğu yoktur .

FRP, zorunlu eşzamanlılığı rahatsız eden teorik ve pragmatik sıçanların yuvasından kaçmadan eşzamanlı olması da olağandışıdır. Anlamsal olarak, FRP'nin eşzamanlılığı ince taneli , kararlı ve süreklidir . (Uygulamadan değil anlamdan bahsediyorum. Bir uygulama eşzamanlılık veya paralellik içerebilir veya içermeyebilir.) Anlamsal belirlilik, hem titiz hem de gayri resmi akıl yürütme için çok önemlidir. Eşzamanlılık, zorunlu programlamaya (belirsiz olmayan serpiştirme nedeniyle) muazzam bir karmaşıklık katmakla birlikte, FRP'de zahmetsizdir.

Peki, FRP nedir? Siz kendiniz icat etmiş olabilirsiniz. Şu fikirlerle başlayın:

  • Dinamik / gelişen değerler (yani, "zaman içindeki değerler") kendi içlerinde birinci sınıf değerlerdir. Bunları tanımlayabilir ve birleştirebilir, işlevlerin içine ve dışına aktarabilirsiniz. Bunlara "davranışlar" adını verdim.

  • Davranışlar, sabit (statik) davranışlar ve zaman (saat gibi) gibi birkaç ilkel öğeden oluşur ve daha sonra sıralı ve paralel kombinasyonla oluşturulur. n davranışları, n-ary fonksiyonu (statik değerlerde), "nokta-bilge", yani zaman içinde sürekli uygulanarak birleştirilir.

  • Ayrık fenomenleri hesaba katmak için, her biri bir oluşum akışına (sonlu veya sonsuz) sahip başka bir tür "olay" türüne sahip olun. Her oluşumun ilişkili bir zamanı ve değeri vardır.

  • Tüm davranışların ve olayların inşa edilebileceği kompozisyon terimleri bulmak için bazı örneklerle oynayın. Yapıyı daha genel / basit parçalara ayırın.

  • Sağlam bir zeminde olduğunuzu bilmeniz için, tüm modele, anlamsal semantik tekniğini kullanarak bir kompozisyon temeli verin; b) her ilkel ve operatör, bileşenlerin anlamlarının bir fonksiyonu olarak basit ve kesin bir anlama sahiptir. Uygulama hususlarını asla keşif sürecinize karıştırmayın. Bu açıklama sizin için anlamsız ise, (a) Tip sınıfı morfizmlerle birlikte tasarım , (b) Push-pull fonksiyonel reaktif programlama (uygulama bitlerini göz ardı ederek) ve (c) Denotational Semantics Haskell wikibooks sayfasına bakın.. İhbarsal anlambilimin iki kurucusu Christopher Strachey ve Dana Scott'tan iki parçası olduğunu unutmayın: daha kolay ve daha kullanışlı Strachey kısmı ve daha zor ve daha az kullanışlı (yazılım tasarımı için) Scott kısmı.

Bu ilkelere bağlı kalırsanız, FRP ruhunda az çok bir şey elde etmenizi beklerim.

Bu ilkeleri nereden aldım? Yazılım tasarımında hep aynı soruyu soruyorum: "bu ne anlama geliyor?". Seslendirme semantiği bana bu soru için kesin bir çerçeve verdi ve estetiğime uyan bir çerçeve verdi (her ikisi de beni tatmin etmeyen operasyonel veya aksiyomatik semantiklerden farklı olarak). Bu yüzden kendime davranışların ne olduğunu sordum? Kısa süre sonra, zorunlu hesaplamanın geçici olarak ayrık doğasının , davranışın kendisinin doğal bir tanımından ziyade, belirli bir makine tarzına bir konaklama olduğunu fark ettim . Aklıma gelen davranışın en basit kesin açıklaması basitçe "(sürekli) zamanın fonksiyonu", yani benim modelim. Nefis bir şekilde, bu model sürekli, deterministik eşzamanlılığı kolaylıkla ve zarafetle ele alır.

Bu modeli doğru ve verimli bir şekilde uygulamak oldukça zordu, ancak bu başka bir hikaye.


78
Fonksiyonel reaktif programlamanın farkındayım. Kendi araştırmamla ilgili görünüyor (interaktif istatistiksel grafiklerde) ve eminim ki fikirlerin çoğu işim için yararlı olacaktır. Ancak, dili geçmeyi çok zor buluyorum - neler olduğunu anlamak için gerçekten "anlamsal anlambilim" ve "tip sınıf morfizmleri" hakkında bilgi edinmeli miyim? Konuya genel bir kitle girişi çok faydalı olacaktır.
hadley

212
@Conal: Ne hakkında konuştuğunuzu açıkça biliyorsunuz, ancak diliniz hesaplamalı matematikte doktora yaptığımı varsayıyor, ki bilmiyorum. Sistem mühendisliğinde bir geçmişe ve bilgisayar ve programlama dilleri konusunda 20 yıldan fazla deneyime sahibim, yine de yanıtınızın beni şaşırttığını hissediyorum. Yanıtınızı İngilizce olarak yeniden göndermenize meydan
okuyorum

50
@ minplay.dk: Düşünceleriniz bana özellikle neyi anlamadığınız konusunda devam etmem için fazla bir şey vermiyor ve hangi İngilizce alt kümesini aradığınız konusunda çılgınca tahminlerde bulunmak istemiyorum. Bununla birlikte, sizi özellikle yukarıdaki açıklamamın hangi yönlerini açtığınızı söylemeye davet ediyorum, böylece ben ve diğerleri size yardımcı olabiliriz. Örneğin, tanımlamak istediğiniz belirli kelimeler veya referansların eklenmesini istediğiniz kavramlar var mı? Yazılarımın anlaşılırlığını ve erişilebilirliğini arttırmaktan gerçekten hoşlanıyorum.
Conal

27
"Determinacy" / "determinate", tek ve iyi tanımlanmış bir doğru değer olduğu anlamına gelir. Buna karşılık, neredeyse tüm zorunlu eşzamanlılık biçimleri, bir zamanlayıcıya veya bakıp bakmamanıza bağlı olarak farklı yanıtlar verebilir ve hatta kilitlenebilir. "Anlamsal" (ve daha spesifik olarak "anlamsal"), "operasyonel" (cevabın nasıl hesaplandığı veya ne tarafından ne kadar alan ve / veya zaman tüketildiği) aksine, bir ifadenin veya gösterimin değerini ("ifade") ifade eder. tür makine).
Conal

18
@ Mindplay.dk ile hemfikirim, ancak uzun süredir bu alanda olmakla övünemiyorum. Ne hakkında konuştuğunuzu biliyormuş gibi görünse de, bana bunun ne olduğuna dair hızlı, kısa ve basit bir anlayış vermedi, çünkü SO'da beklemek için yeterince şımarıktım. Bu cevap öncelikle beni ilk soruya cevap vermeden tonlarca yeni soruya yöneltti. Alanda hâlâ görece cahil olmanın deneyimini paylaşmanın, size gerçekten ne kadar basit ve kısa olmanız gerektiğine dair bir fikir vereceğini umuyorum. OP, btw ile benzer bir geçmişe sahibim.
Aske B.Haziran

739

Saf fonksiyonel programlamada hiçbir yan etkisi yoktur. Birçok yazılım türü için (örneğin, kullanıcı etkileşimi olan herhangi bir şey) bir düzeyde yan etkiler gereklidir.

Fonksiyonel bir tarzı korurken davranış gibi yan etki elde etmenin bir yolu, fonksiyonel reaktif programlama kullanmaktır. Bu, fonksiyonel programlama ve reaktif programlamanın birleşimidir. (Bağlantı verdiğiniz Wikipedia makalesi, ikincisiyle ilgilidir.)

Reaktif programlamanın ardındaki temel fikir, "zaman içinde" bir değeri temsil eden belirli veri türlerinin olmasıdır. Bu zaman içinde değişen değerleri içeren hesaplamalar, zaman içinde değişen değerlere sahip olacaktır.

Örneğin, fare koordinatlarını zaman içinde bir tamsayı değeri çifti olarak gösterebilirsiniz. Diyelim ki böyle bir şeyimiz var (bu sahte kod):

x = <mouse-x>;
y = <mouse-y>;

Herhangi bir zamanda, x ve y, farenin koordinatlarına sahip olacaktır. Reaktif olmayan programlamanın aksine, bu atamayı yalnızca bir kez yapmamız gerekir ve x ve y değişkenleri otomatik olarak "güncel" kalır. Bu nedenle reaktif programlama ve fonksiyonel programlama birlikte çok iyi çalışır: reaktif programlama, değişkenleri mutasyona uğratma gereksinimini ortadan kaldırırken, değişken mutasyonlarla yapabileceğiniz şeylerin çoğunu yapmanıza izin verir.

Daha sonra buna dayalı bazı hesaplamalar yaparsak, ortaya çıkan değerler de zaman içinde değişen değerler olacaktır. Örneğin:

minX = x - 16;
minY = y - 16;
maxX = x + 16;
maxY = y + 16;

Bu örnekte, minXfare işaretçisinin x koordinatından her zaman 16 daha az olacaktır. Reaktif bilinçli kütüphaneler ile şöyle bir şey söyleyebilirsiniz:

rectangle(minX, minY, maxX, maxY)

Fare işaretçisinin etrafına 32x32 bir kutu çizilecek ve hareket ettiği her yerde izleyecektir.

İşte fonksiyonel reaktif programlama hakkında oldukça iyi bir makale .


25
Öyleyse reaktif programlama bir tür bildirimsel programlamadır?
troelskn

31
> Öyleyse reaktif programlama bir tür bildirimsel programlamadır? Fonksiyonel reaktif programlama, bir deklaratif programlama biçimi olan bir fonksiyonel programlama şeklidir.
Conal

7
@ user712092 Pek değil, hayır. Örneğin, sqrt(x)C ile makronuzu ararsam, bu sqrt(mouse_x())beni hesaplar ve bir çift verir. Gerçek bir işlevsel reaktif sistemde, sqrt(x)yeni bir "zaman içinde iki katına" dönecektir. Bir FR sistemini simüle #defineetmeye çalışsaydınız, değişkenleri makrolar lehine yutmanız gerekirdi. FR sistemleri de genellikle yalnızca yeniden hesaplanması gerektiğinde bir şeyleri yeniden hesaplar, buna karşılık makroları kullanmak her şeyi alt ifadelere kadar sürekli olarak yeniden değerlendireceğiniz anlamına gelir.
Laurence Gonsalves

4
"Birçok yazılım türü için (örneğin, kullanıcı etkileşimi olan herhangi bir şey) bazı düzeylerde yan etkiler gereklidir." Ve belki de sadece uygulama düzeyinde. Saf, tembel fonksiyonel programlamanın uygulanmasında birçok yan etki vardır ve paradigmanın başarılarından biri bu etkilerin çoğunu programlama modelinden uzak tutmaktır. İşlevsel kullanıcı arabirimlerine yönelik kendi forumlarım, bunların tamamen yan etkiler olmadan da programlanabileceğini gösteriyor.
Conal

4
@tieTYT x hiçbir zaman yeniden atanmaz / değiştirilmez. x'in değeri zaman içindeki değerlerin dizisidir. Buna bakmanın bir başka yolu, x gibi bir sayı gibi "normal" bir değere sahip olmak yerine, x'in değerinin (kavramsal olarak) parametre olarak zaman alan bir işlev olmasıdır. (Bu biraz aşırı basitleştirme. Fare konumu gibi şeylerin geleceğini tahmin etmenize izin verecek zaman değerleri oluşturamazsınız.)
Laurence Gonsalves

144

Nasıl bir şey olduğuna dair ilk sezgiye ulaşmanın kolay bir yolu, programınızın bir e-tablo olduğunu ve tüm değişkenlerinizin hücre olduğunu hayal etmektir. Bir e-tablodaki hücrelerden herhangi biri değişirse, o hücreye başvuran hücreler de değişir. FRP ile aynı şey. Şimdi bazı hücrelerin kendi başlarına değiştiğini (veya daha doğrusu, dış dünyadan alındığını) düşünün: GUI durumunda, farenin konumu iyi bir örnek olacaktır.

Bu mutlaka çok özlüyor. Bir FRP sistemi kullandığınızda metafor oldukça hızlı bir şekilde parçalanır. Birincisi, genellikle ayrık olayları modelleme girişimleri de vardır (örneğin, tıklanan fare). Bunu buraya sadece size nasıl bir şey olduğu hakkında bir fikir vermek için koyuyorum.


3
Son derece uygun bir örnek. Teorik şeylere sahip olmak harika ve belki de bazı insanlar bunun temellerini bir topraklama örneğine başvurmadan alıyorlar, ama benim için ne yaptığından başlamam gerekiyor, soyut olduğu gibi değil. Yakın zamanda aldığım (Netflix'in Rx görüşmelerinden!) RP (ya da Rx, yine de), bu "değişen değerleri" birinci sınıf yapıyor ve onlarla ilgili akıl yürütmenize ya da onlarla bir şeyler yapan işlevler yazmanıza izin veriyor. İsterseniz elektronik tablolar veya hücreler oluşturmak için işlevleri yazın. Ve bir değer sona erdiğinde (gider) işler ve otomatik olarak temizlemenizi sağlar.
Benjohn

Bu örnek, olaylara dayalı programlama ve akıllı yönlendirme kullanma bağımlılıklarını bildirdiğiniz reaktif yaklaşım arasındaki farkı vurgular.
kinjelom

131

Benim için sembolün yaklaşık 2 farklı anlamı var =:

  1. Matematik olarak x = sin(t)vasıtasıyla, yani xbir farklı isim için sin(t). Yani yazmak x + yaynı şey sin(t) + y. Fonksiyonel reaktif programlama bu bakımdan matematik gibidir: yazarsanız x + y, tkullanıldığı anda değeri ne olursa olsun hesaplanır .
  2. C benzeri programlama dillerinde (zorunlu diller) x = sin(t)bir ödevdir: ödev sırasında alınan değerix sakladığı anlamına gelir . sin(t)

5
İyi açıklama. Ben de FRP anlamında "zaman" eklemek normalde "harici giriş herhangi bir değişiklik" olduğunu düşünüyorum. Harici bir kuvvet FRP girişini her değiştirdiğinde, "zamanı" ileriye taşıdınız ve değişiklikten etkilenen her şeyi yeniden hesaplayın.
Didier A.

4
Matematik olarak x = sin(t)vasıtasıyla xdeğeri sin(t)verilir için t. Öyle değil için farklı bir ad sin(t)olarak işlevi. Aksi halde olur x(t) = sin(t).
Dmitri Zaitsev

+ Dmitri Zaitsev Eşittir işaretinin matematikte birçok anlamı vardır. Bunlardan biri, sol tarafı her gördüğünüzde sağ tarafla değiştirebileceğinizdir . Örneğin 2 + 3 = 5veya a**2 + b**2 = c**2.
user712092

71

Tamam, arka plan bilgisinden ve işaret ettiğiniz Wikipedia sayfasını okurken, reaktif programlamanın veri akışı hesaplama gibi bir şey olduğu, ancak belirli harici "uyaranların" bir dizi düğümün ateşlenmesini ve hesaplamalarını gerçekleştirmesini tetiklediği görülüyor.

Bu, kullanıcı arayüzü kontrolüne (örneğin, bir müzik çalma uygulamasındaki ses seviyesi kontrolüne) dokunmanın çeşitli ekran öğelerini ve gerçek ses çıkışı seviyesini güncellemesinin gerekebileceği UI tasarımı için oldukça uygundur. Yönlendirilmiş bir grafikteki bir düğümle ilişkili değerin değiştirilmesine karşılık gelen birimi (bir kaydırıcı, diyelim) değiştirdiğinizde.

Bu "hacim değeri" düğümünden kenarları olan çeşitli düğümler otomatik olarak tetiklenir ve gerekli tüm hesaplamalar ve güncellemeler doğal olarak uygulama boyunca dalgalanır. Uygulama kullanıcı uyaranına "tepki verir". İşlevsel reaktif programlama sadece bu fikrin işlevsel bir dilde veya genellikle işlevsel bir programlama paradigması içinde uygulanması olacaktır.

"Dataflow computing" hakkında daha fazla bilgi için Wikipedia'da veya favori arama motorunuzu kullanarak bu iki kelimeyi arayın. Genel fikir şudur: Program, her biri basit bir hesaplama yapan yönlendirilmiş bir düğüm grafiğidir. Bu düğümler, bazı düğümlerin çıkışlarını, diğerlerinin girişlerine sağlayan grafik bağlantıları ile birbirine bağlanır.

Bir düğüm tetiklendiğinde veya hesaplamasını gerçekleştirdiğinde, çıkışlarına bağlı düğümlerin karşılık gelen girişleri "tetiklenir" veya "işaretlenir". Tüm girişlerin tetiklendiği / işaretlendiği / kullanılabilir olduğu herhangi bir düğüm otomatik olarak tetiklenir. Grafik, reaktif programlamanın tam olarak nasıl uygulandığına bağlı olarak örtülü veya açık olabilir.

Düğümler paralel ateşleme olarak görülebilir, ancak genellikle seri olarak veya sınırlı paralellikle yürütülürler (örneğin, bunları yürüten birkaç iş parçacığı olabilir). Ünlü bir örnek (IIRC), bir veya daha fazla yürütme birimi aracılığıyla grafikteki düğümlerin yürütülmesini zamanlamak için etiketli bir veri mimarisi kullanan Manchester Dataflow Machine idi . Veri akışı hesaplaması, hesaplamaları zaman uyumsuz olarak hesaplamaya yol açan hesaplamaları tetiklemenin bir saat (veya saatler) tarafından yönetilmeye çalışılmasından daha iyi çalıştığı durumlar için oldukça uygundur.

Reaktif programlama, bu "yürütme çağlayanı" fikrini içe aktarır ve programı veri akışı benzeri bir şekilde düşünür, ancak bazı düğümlerin "dış dünyaya" bağlanması ve yürütme şelalelerinin bu duyusal olarak tetiklenmesi şartıyla benzeri düğümler değişir. Programın yürütülmesi daha sonra karmaşık bir refleks yayına benzer bir şey gibi görünecektir. Program uyaranlar arasında temel olarak sapsız olabilir veya olmayabilir veya uyaranlar arasında temel olarak sapsız bir duruma geçebilir.

"reaktif olmayan" programlama, yürütme akışının ve harici girdilerle ilişkinin çok farklı bir görünümü ile programlama olacaktır. İnsanların dış girdilere yanıt veren herhangi bir şeyi "tepki" verdikleri söylenmeye meyilli olacağı için, bu biraz öznel olabilir. Ancak o şeyin ruhuna bakıldığında, bir olay kuyruğunu sabit bir aralıkta yoklayan ve işlevlere (veya iş parçacıklarına) bulunan tüm olayları gönderen bir program daha az reaktiftir (çünkü yalnızca belirli bir aralıkta kullanıcı girdisine katılır). Yine, buradaki şeyin ruhu: hızlı bir yoklama aralığıyla bir yoklama uygulamasını çok düşük bir seviyede bir sisteme yerleştirmeyi düşünebilir ve bunun üzerine reaktif bir şekilde programlayabilirsiniz.


1
Tamam, yukarıda iyi cevaplar var. Yazımı kaldırmalı mıyım? İki ya da üç kişinin hiçbir şey eklemediğini görürsem, yardımcı sayısı artmadıkça silerim. Değerli bir şey katmadıkça burada bırakmanın bir anlamı yok.
Thomas Kammeyer

3
veri akışından bahsettiniz, böylece biraz IMHO katıyor.
Rainer Joswig

QML olması gerektiği budur, öyle görünüyor;)
mlvljr

3
Benim için bu cevap anlaşılması en kolaydı, çünkü özellikle "uygulama boyunca dalgalanma" ve "duyusal benzeri düğümler" gibi doğal analogların kullanılması. Harika!
Akseli Palén

1
ne yazık ki, Manchester Dataflow Machine bağlantısı öldü.
Pac0

65

FRP hakkında birçok sayfa okuduktan sonra nihayet FRP hakkındaki bu aydınlatıcı yazı ile karşılaştım, sonunda FRP'nin gerçekte ne olduğunu anlamamı sağladı.

Heinrich Apfelmus'un (reaktif muz yazarı) aşağıda alıntı yapıyorum.

Fonksiyonel reaktif programlamanın özü nedir?

Yaygın bir cevap, “FRP tamamen bir sistemi değişebilir durum yerine zamanla değişen işlevler açısından tanımlamakla ilgilidir” ve bu kesinlikle yanlış olmaz. Anlamsal bakış açısı budur. Ancak bence, daha derin, daha tatmin edici bir cevap aşağıdaki tamamen sözdizimsel ölçüt tarafından verilir:

Fonksiyonel reaktif programlamanın özü, bir değerin dinamik davranışını beyan anında tamamen belirtmektir.

Örneğin, bir sayaç örneği alın: sayacı artırmak veya azaltmak için kullanılabilen “Yukarı” ve “Aşağı” etiketli iki düğmeniz var. Zorunlu olarak, önce bir başlangıç ​​değeri belirtir ve ardından bir düğmeye her basıldığında bunu değiştirirsiniz; böyle bir şey:

counter := 0                               -- initial value
on buttonUp   = (counter := counter + 1)   -- change it later
on buttonDown = (counter := counter - 1)

Mesele şu ki, beyan sırasında sadece sayaç için başlangıç ​​değeri belirtilir; sayacın dinamik davranışı program metninin geri kalanında gizlidir. Buna karşılık, fonksiyonel reaktif programlama, bildirim sırasındaki tüm dinamik davranışı şu şekilde belirtir:

counter :: Behavior Int
counter = accumulate ($) 0
            (fmap (+1) eventUp
             `union` fmap (subtract 1) eventDown)

Sayacın dinamiklerini anlamak istediğinizde, sadece tanımına bakmanız gerekir. Olabilecek her şey sağ tarafta görünecektir. Bu, sonraki bildirimlerin daha önce bildirilen değerlerin dinamik davranışını değiştirebileceği zorunlu yaklaşımın aksine.

Yani, içinde benim anlayış bir FRP programı denklemlerin bir dizi: resim açıklamasını buraya girin

j ayrık: 1,2,3,4 ...

fbağlıdır tbu dış uyaranları modellemek için possiblilty birleştirir böylece

programın tüm durumu değişkenlerle kapsüllenir x_i

CTP kütüphane alarak başka bir deyişle, zaman ilerliyor ilgilenir jiçin j+1.

Bu videoda bu denklemleri çok daha ayrıntılı olarak açıklıyorum .

DÜZENLE:

Orijinal yanıttan yaklaşık 2 yıl sonra, son zamanlarda FRP uygulamalarının başka bir önemli yönü olduğu sonucuna vardım. Önemli bir pratik sorunu çözmeleri (ve genellikle çözmeleri) gerekir: önbellek geçersiz kılma .

x_i-S denklemleri bir bağımlılık grafiğini tanımlar. Zamandaki x_ideğişikliklerin bazılarının jo zaman tüm diğer x_i'değerlerin j+1güncellenmesi gerekmediği için, tüm bağımlılıkların yeniden hesaplanması gerekmez, çünkü bazıları x_i'bağımsız olabilir x_i.

Ayrıca, x_ideğişiklik yapan -s kademeli olarak güncellenebilir. Örneğin en harita çalışmasını düşünün izin f=g.map(_+1)Scala, içinde fve gvardır Listiçinde Ints. Burada fkarşılık gelir x_i(t_j)ve göyle x_j(t_j). Şimdi bir elementi başarabilirsem, goradaki maptüm elementler için operasyonu yürütmek israf olacaktır g. Bazı FRP uygulamaları (örneğin reflex-frp ) bu sorunu çözmeyi amaçlamaktadır. Bu sorun, artımlı hesaplama olarak da bilinir .

Başka bir deyişle, FRP'deki davranışlar ( x_i-s) önbelleğe alınmış hesaplamalar olarak düşünülebilir. x_iBazı f_i-s'ların değişmesi durumunda bu önbellekleri ( -s) etkili bir şekilde geçersiz kılmak ve yeniden hesaplamak FRP motorunun görevidir .


4
Ayrık denklemlerle gidene kadar oradaydım . FRP'nin kurucu fikri sürekli bir zaman , hiçbir " j+1" olmadığı zamandı . Bunun yerine, sürekli zamanın işlevlerini düşünün. Newton, Leibniz ve diğerlerinin bize gösterdiği gibi, bu işlevleri farklı şekilde tanımlamak, ancak sürekli olarak, ODE integrallerini ve sistemlerini kullanarak derinden kullanışlı (ve gerçek anlamda "doğal"). Aksi takdirde, nesnenin kendisi yerine bir yaklaşım algoritması (ve fakir bir algoritma) açıklıyorsunuz.
Conal

HTML şablonlama ve düzen kısıtlamaları dil layx , FRP öğelerini ifade ediyor gibi görünüyor.

@Conal bu bana FRP'nin ODE'lerden nasıl farklı olduğunu merak ediyor. Nasıl farklılar?
jhegedus

@jhegedus Bu entegrasyonda (muhtemelen özyinelemeli, yani ODE'ler) bütünüyle değil, FRP'nin yapı taşlarından birini sağlar. FRP kelime dağarcığının her bir unsuru (entegrasyon dahil ancak bunlarla sınırlı olmamak üzere), sürekli zaman açısından tam olarak açıklanmaktadır. Bu açıklama yardımcı olur mu?
Conal


29

Feragatname: Cevabım Javascript için bir 'reaktif programlama' kütüphanesi olan rx.js bağlamında.

İşlevsel programlamada, bir koleksiyonun her bir öğesini yinelemek yerine, koleksiyonun kendisine daha yüksek dereceli işlevler (HoF'ler) uygularsınız. Dolayısıyla, FRP'nin arkasındaki fikir, her bir olayı işlemek yerine, bir olay akışı (gözlemlenebilir * ile uygulanır) oluşturmak ve bunun yerine HoF'ları uygulamaktır. Bu şekilde sistemi, yayıncıları abonelere bağlayan veri boru hatları olarak görselleştirebilirsiniz.

Gözlenebilir bir kullanmanın başlıca avantajları şunlardır:
i) durumu kodunuzdan uzaklaştırır; örneğin, olay işleyicisinin yalnızca her 'n'th olay için kovulmasını veya ilk' n 'olaylarından sonra tetiklenmeyi durdurmasını istiyorsanız, veya yalnızca ilk 'n' olaylarından sonra tetiklemeye başlayın, sayaçları ayarlamak, güncellemek ve kontrol etmek yerine HoF'leri (sırasıyla filter, takeUntil, atla) kullanabilirsiniz.
ii) kodun yerini iyileştirir - bir bileşenin durumunu değiştiren 5 farklı olay işleyiciniz varsa, gözlemlenebilirlerini birleştirebilir ve bunun yerine birleştirilmiş gözlemlenebilirde tek bir olay işleyicisi tanımlayabilir ve 5 olay işleyicisini 1 etkili bir şekilde birleştirebilirsiniz. tek bir işleyicide mevcut olduğundan, tüm sisteminizdeki hangi olayların bir bileşeni etkileyebileceğine karar vermek kolaydır.

  • Gözlemlenebilir, Yinelenebilir Bir İkili.

Yinelenebilir, tembel olarak tüketilen bir dizidir - her öğe, kullanmak istediği zaman yineleyici tarafından çekilir ve dolayısıyla numaralandırma tüketici tarafından yönlendirilir.

Gözlenebilir tembel olarak üretilen bir sekanstır - sekansa her eklendiğinde her bir madde gözlemciye itilir ve dolayısıyla numaralandırma üretici tarafından yönlendirilir.


1
Bir gözlemlenebilirin bu basit tanımı ve tekrarlanabilirlerden ayrılması için çok teşekkür ederim . Gerçek bir anlayış kazanmak için karmaşık bir kavramı iyi bilinen ikili konsepti ile karşılaştırmak genellikle çok yararlı olur.

2
"Yani FRP'nin arkasındaki fikir, her bir olayı işlemek yerine, bir olay akışı (gözlemlenebilir * ile uygulanır) oluşturmak ve bunun yerine HoF'ları uygulamaktır." Yanılıyor olabilirim ama bunun aslında FRP değil, yine de zorunlu kod ile kullanılması amaçlanmışken HoF (işlevsel!) İle işlevsel operasyonlara izin veren Observer tasarım deseni üzerinde güzel bir soyutlama olduğuna inanıyorum. Konu üzerine tartışma - lambda-the-ultimate.org/node/4982
nqe

18

Dostum, bu harika bir fikir! Neden 1998'de bunu bulamadım? Her neyse, işte Fran öğreticisini yorumum . Öneriler çok hoş geldiniz, buna dayalı bir oyun motoru başlatmayı düşünüyorum.

import pygame
from pygame.surface import Surface
from pygame.sprite import Sprite, Group
from pygame.locals import *
from time import time as epoch_delta
from math import sin, pi
from copy import copy

pygame.init()
screen = pygame.display.set_mode((600,400))
pygame.display.set_caption('Functional Reactive System Demo')

class Time:
    def __float__(self):
        return epoch_delta()
time = Time()

class Function:
    def __init__(self, var, func, phase = 0., scale = 1., offset = 0.):
        self.var = var
        self.func = func
        self.phase = phase
        self.scale = scale
        self.offset = offset
    def copy(self):
        return copy(self)
    def __float__(self):
        return self.func(float(self.var) + float(self.phase)) * float(self.scale) + float(self.offset)
    def __int__(self):
        return int(float(self))
    def __add__(self, n):
        result = self.copy()
        result.offset += n
        return result
    def __mul__(self, n):
        result = self.copy()
        result.scale += n
        return result
    def __inv__(self):
        result = self.copy()
        result.scale *= -1.
        return result
    def __abs__(self):
        return Function(self, abs)

def FuncTime(func, phase = 0., scale = 1., offset = 0.):
    global time
    return Function(time, func, phase, scale, offset)

def SinTime(phase = 0., scale = 1., offset = 0.):
    return FuncTime(sin, phase, scale, offset)
sin_time = SinTime()

def CosTime(phase = 0., scale = 1., offset = 0.):
    phase += pi / 2.
    return SinTime(phase, scale, offset)
cos_time = CosTime()

class Circle:
    def __init__(self, x, y, radius):
        self.x = x
        self.y = y
        self.radius = radius
    @property
    def size(self):
        return [self.radius * 2] * 2
circle = Circle(
        x = cos_time * 200 + 250,
        y = abs(sin_time) * 200 + 50,
        radius = 50)

class CircleView(Sprite):
    def __init__(self, model, color = (255, 0, 0)):
        Sprite.__init__(self)
        self.color = color
        self.model = model
        self.image = Surface([model.radius * 2] * 2).convert_alpha()
        self.rect = self.image.get_rect()
        pygame.draw.ellipse(self.image, self.color, self.rect)
    def update(self):
        self.rect[:] = int(self.model.x), int(self.model.y), self.model.radius * 2, self.model.radius * 2
circle_view = CircleView(circle)

sprites = Group(circle_view)
running = True
while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        if event.type == KEYDOWN and event.key == K_ESCAPE:
            running = False
    screen.fill((0, 0, 0))
    sprites.update()
    sprites.draw(screen)
    pygame.display.flip()
pygame.quit()

Kısacası: Eğer her bileşen bir sayı gibi ele alınabiliyorsa, tüm sistem matematik denklemi gibi ele alınabilir, değil mi?


1
Bu biraz geç, ama her neyse ... Frag, FRP kullanan bir oyundur .
arx

14

Paul Hudak'ın Haskell İfade Okulu kitabı sadece Haskell için iyi bir tanıtım değil, aynı zamanda FRP'ye de oldukça zaman harcıyor. FRP'ye yeni başlayan biriyseniz, size FRP'nin nasıl çalıştığını anlamanız için tavsiye ederim.

Ayrıca Haskell Müzik Okulu, bu kitabın yeni bir yeniden yazılmasına benziyor (2011'de yayınlandı, 2014'de güncellendi) .


10

Önceki cevaplara göre, matematiksel olarak, sadece daha yüksek bir sırada düşünüyoruz gibi görünüyor. X türüne sahip bir x değerini düşünmek yerine, x : TX fonksiyonunu düşünüyoruz , burada T , doğal sayılar, tamsayılar veya süreklilik olsun, zaman türüdür. Şimdi programlama dilinde y : = x + 1 yazdığımızda aslında y ( t ) = x ( t ) + 1 denklemini kastediyoruz .


9

Belirtildiği gibi bir elektronik tablo gibi davranır. Genellikle olay güdümlü bir çerçeveye dayanır.

Tüm "paradigmalar" da olduğu gibi, bu yenilik tartışmalıdır.

Aktörlerin dağıtılmış akış ağları deneyimlerimden, düğüm ağında genel bir devlet tutarlılığı sorununa kolayca avlanabilir, yani garip döngülerde çok fazla salınım ve tuzakla sonuçlanırsınız.

Bazı semantikler referans döngüleri veya yayınlar ima ettiğinden bu kaçınılmazdır ve aktörler ağı öngörülemeyen bazı durumlarda yakınsadıkça (veya değil) oldukça kaotik olabilir.

Benzer şekilde, iyi tanımlanmış kenarlara sahip olmasına rağmen bazı durumlara ulaşılamayabilir, çünkü küresel durum çözümden uzaklaşır. 2 + 2, 2'lerin 2 olduğu zamana ve bu şekilde kalıp kalmalarına bağlı olarak 4 olabilir veya olmayabilir. Elektronik tablolar senkron saatlere ve döngü algılamaya sahiptir. Dağıtık aktörler genellikle bunu yapmazlar.

Hepsi eğlenceli :).



7

Andre Staltz'un bu makalesi , şimdiye kadar gördüğüm en iyi ve en net açıklama.

Makaleden bazı alıntılar:

Reaktif programlama, eşzamansız veri akışlarıyla programlama yapıyor.

Bunun da ötesinde, bu akışlardan herhangi birini birleştirmek, oluşturmak ve filtrelemek için inanılmaz bir işlev araç kutusu verilir.

İşte makalenin bir parçası olan fantastik diyagramlara bir örnek:

Tıklama etkinliği akış şeması


5

Bu, zaman içindeki matematiksel veri dönüşümleriyle (ya da zamana aldırmadan) ilgilidir.

Kodda bu, fonksiyonel saflık ve bildirimsel programlama anlamına gelir.

Devlet hataları standart zorunluluk paradigmasında büyük bir sorundur. Çeşitli kod parçaları, program yürütme işleminde farklı "zamanlarda" paylaşılan bazı durumları değiştirebilir. Bunun üstesinden gelmek zor.

FRP'de (deklaratif programlamada olduğu gibi) verilerin bir durumdan diğerine nasıl dönüştüğünü ve neyi tetiklediğini açıklarsınız. Bu, zamanı görmezden gelmenize izin verir, çünkü işleviniz yalnızca girdilerine tepki verir ve yeni bir tane oluşturmak için mevcut değerlerini kullanır. Bu, durumun, dönüşüm düğümlerinin grafiğinde (veya ağacında) bulunduğu ve fonksiyonel olarak saf olduğu anlamına gelir.

Bu, karmaşıklığı ve hata ayıklama süresini büyük ölçüde azaltır.

Matematikte A = B + C ile bir programda A = B + C arasındaki farkı düşünün. Matematikte asla değişmeyecek bir ilişkiyi tarif ediyorsun. Bir programda, "Şu anda" A'nın B + C olduğunu söylüyor. Ancak bir sonraki komut B ++ olabilir, bu durumda A B + C'ye eşit değildir. Matematikte veya deklaratif programlamada, ne zaman olursa olsun, A daima B + C'ye eşit olacaktır.

Böylece, paylaşılan durumun karmaşıklıklarını kaldırarak ve zaman içinde değerleri değiştirerek. Programın akıl yürütmesi çok daha kolaydır.

EventStream bir EventStream + bazı dönüştürme işlevidir.

Davranış bir EventStream + Bellekteki bir değerdir.

Olay tetiklendiğinde, değer dönüştürme işlevi çalıştırılarak güncellenir. Bunun ürettiği değer davranışlar belleğinde saklanır.

Davranışlar, N diğer davranış üzerinde dönüşüm olan yeni davranışlar üretmek için oluşturulabilir. Bu oluşturulan değer, girdi olayları (davranışlar) ateş ettikçe yeniden hesaplanacaktır.

"Gözlemciler vatansız oldukları için, sürükleme örneğindeki gibi bir durum makinesini simüle etmek için çoğu zaman bunlara ihtiyacımız var. Durumu, değişken değişken gibi tüm gözlemciler tarafından erişilebilir olduğu yerde kaydetmemiz gerekiyor."

Alıntı - Gözlemci Deseni Onaylama http://infoscience.epfl.ch/record/148043/files/DeprecatingObserversTR2010.pdf


Açıklayıcı programlama hakkında tam da böyle hissediyorum ve siz sadece fikri benden daha iyi tarif ediyorsunuz.
neevek

2

Reaktif Programlama ile ilgili kısa ve net açıklama Cyclejs - Reactive Programming'de görünür, basit ve görsel örnekler kullanır.

Bir [modül / Bileşen / nesne] reaktiftir , harici olaylara tepki vererek kendi durumunun yönetilmesinden tamamen sorumlu olduğu anlamına gelir.

Bu yaklaşımın yararı nedir? Bu kontrolün tersine çevrilmesidir, çünkü esas olarak [modül / Bileşen / nesne] kendisinden sorumludur, halka açık olanlara karşı özel yöntemler kullanarak kapsüllemeyi geliştirir.

İyi bir başlangıç ​​noktasıdır, tam bir bilgi kaynağı değildir. Oradan daha karmaşık ve derin kağıtlara atlayabilirsiniz.


0

.NET için Rx, Reaktif Uzantıları'na bakın. IEnumerable ile temelde bir akıştan 'çektiğinizi' belirtiyorlar. IQueryable / IEnumerable üzerinden Linq sorguları, sonuçları bir kümeden 'emen' ayarlanmış işlemlerdir. Ancak IObservable üzerinden aynı operatörlerle, 'tepki veren' Linq sorguları yazabilirsiniz.

Örneğin, gibi bir Linq sorgusu yazabilirsiniz (mO <100 ve mY <100'ün yeni Nokta (mX, mY) seçtiği MyObservableSetOfMouseMovements içindeki m'den).

ve Rx uzantıları ile, hepsi bu: Gelen fare hareketleri akışına tepki veren ve 100.100 kutusunun içine her geldiğinizde çizim yapan kullanıcı arayüzü kodunuz var ...


0

FRP, İşlevsel programlama (her şeyin bir fikri olduğu üzerine inşa edilen programlama paradigması) ve reaktif programlama paradigmasının (her şeyin bir akış olduğu (gözlemci ve gözlemlenebilir felsefe) fikri üzerine inşa edilmiş) bir kombinasyonudur. Dünyanın en iyisi olması gerekiyordu.

Başlamak için reaktif programlama hakkındaki Andre Staltz yayınına göz atın.

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.