Што такое (функцыянальнае) рэактыўнае праграмаванне?

Я прачытаў артыкул Вікіпедыі аб рэактыўным праграмаванні . Я таксама прачытаў невялікую артыкул аб функцыянальным рэактыўным праграмаванні . Апісання даволі абстрактныя.

  • Што на практыцы азначае функцыянальнае рэактыўнае праграмаванне (FRP)?
  • Што такое рэактыўнае праграмаванне (у адрозненне ад нереактивного праграмавання?)?

Мой фон - гэта мовы імпэратыву / OO, таму нам будзе ацэнена тлумачэнне, звязанае з гэтай парадыгмай.

1149
22 июня '09 в 19:41 2009-06-22 19:41 зададзены JtR 22 чэрвеня '09 у 19:41 2009-06-22 19:41
@ 19 адказаў

Калі вы хочаце адчуць FRP, вы можаце пачаць са старога Fran tutorial з 1998 года, у якім ёсць аніміраваныя ілюстрацыі. Для дакументаў пачынайце з Functional Reactive Animation , а затым вынікайце спасылках на спасылку публікацыі на маёй хатняй старонцы і FRP на Haskell wiki .

Асабіста мне падабаецца думаць пра тое, што азначае FRP, перш чым вырашаць, як гэта можна рэалізаваць. (Код без спецыфікацыі - гэта адказ без пытання і, такім чынам, "нават не так".) Таму я не апісваю FRP ў тэрмінах прадстаўлення / рэалізацыі, як Томас Да робіць у іншым адказе (графікі, вузлы, рэбры, стральба, выкананне і г.д.). Існуе шмат магчымых стыляў рэалізацыі, але рэалізацыя не кажа пра тое, што такое FRP.

Я сапраўды рэзаніруе з простым апісаннем Laurence G, што FRP ставіцца да "тыпах дадзеных, якія ўяўляюць каштоўнасць" з цягам часу ". Звычайнае імператыўнае праграмаванне фіксуе гэтыя дынамічныя значэння толькі ўскосна, праз стан і мутацыі. Поўная гісторыя (мінулае, сучаснасць, будучыня) не мае паданні першага класа. Больш за тое, толькі дыскрэтна змяняюцца каштоўнасці могуць (ўскосна) захоплівае, паколькі імператыўнага парадыгма часова дыскрэтная. Наадварот, FRP фіксуе гэтыя зменлівыя значэння наўпрост і ня имее ніякіх праблем з пастаянна змяняюцца значэннямі.

FRP таксама незвычайны тым, што ён паралеляў, ня запускаючы тэарэтычнага і прагматычнага гнязда пацукоў, які навязвае імператыў concurrency. Семантычна FRP concurrency з'яўляецца дробназярністым, дэтэрмінаваных і бесперапынным. (Я кажу пра значэнне, а не аб рэалізацыі. Рэалізацыя можа ўключаць ці не ўключаць concurrency або parallelism.) Семантычная пэўнасць вельмі важная для разваг, як строгіх, так і нефармальных. У той час як concurrency дадае велізарную складанасць да імператыўнага праграмавання (з-за недетерминированного чаргавання), ён без намаганняў у FRP.

Такім чынам, што такое FRP? Вы маглі б прыдумаць гэта самі. Пачніце з гэтых ідэй:

  • Дынамічныя / зменлівыя значэння (г.зн. значэння "з часам") з'яўляюцца значэннямі першага класа самі па сабе. Вы можаце вызначыць іх і аб'яднаць, перадаць іх у функцыі і з іх. Я назваў гэтыя рэчы "паводзінамі".

  • Паводзін ствараюцца з некалькіх прымітываў, такіх як пастаяннае (статычнае) паводзіны і час (напрыклад, гадзіны), а затым з паслядоўнай і паралельнай камбінацыяй. n спалучаюцца, ужываючы n-арную функцыю (па статычным значэнняў), "па-кропкі", г.зн. бесперапынна з часам.

  • Для ўліку дыскрэтных з'яў ёсць іншы тып (сям'я) "падзей", кожны з якіх мае паток (канчатковы ці бясконцы) уваходжанняў. Кожная падзея мае звязанае час і значэнне.

  • Каб прыдумаць кампазіцыйны слоўнік, з якога можна пабудаваць усе паводзіны і падзеі, пагуляйце з некаторымі прыкладамі. Працягвайце дэканструяваць на кавалкі, якія з'яўляюцца больш агульнымі / простымі.

  • Каб вы ведалі, што знаходзіцеся на цвёрдай глебе, дайце цэлай мадэлі кампазіцыйную аснову, выкарыстоўваючы тэхніку денотационной семантыкі, якая проста азначае, што (а) кожны тып мае адпаведны просты і дакладны матэматычны тып "значэння" і (б) кожны прымітыў, а аператар мае просты і дакладны сэнс як функцыю значэнняў складнікаў. Ніколі, ніколі не змешвайце меркаванні, звязаныя з укараненнем, у працэсе даследавання. Калі гэта апісанне з'яўляецца тарабаршчыну для вас, пракансультуйцеся (a) Denotational design з морфизмами тыпу класа , (b) Push-pull функцыянальнае рэактыўнае праграмаванне (ігнараванне бітаў рэалізацыі) і (c) Denotational Semantics Haskell wikibooks page . Сцеражыцеся таго, што денотационная семантыка складаецца з двух частак: ад двух яе заснавальнікаў Крыстафера Стрэхи і Даны Скот: больш простая і карысная частка Страхі і больш цяжкая і меней карысная (для распрацоўкі праграмнага забеспячэння) частка Скота.

Калі вы прытрымліваецеся гэтых прынцыпаў, я чакаю, што вы атрымаеце нешта больш-менш у духу FRP.

Дзе я атрымаў гэтыя прынцыпы? У распрацоўцы праграмнага забеспячэння я заўсёды задаю адзін і той жа пытанне: "што гэта значыць?". Денотационная семантыка дала мне выразныя рамкі для гэтага пытання, і той, які адпавядае маёй эстэтыцы (у адрозненне ад аператыўнай або аксиоматической семантыкі, абедзве з якіх пакідаюць мяне нездаволенымі). Таму я спытаў сябе, што такія паводзіны? Неўзабаве я зразумеў, што часовая дыскрэтная прырода імператыўнага вылічэнні - гэта размяшчэнне пэўнага стылю машыны, а не натуральнае апісанне самога паводзін. Найпростае дакладнае апісанне паводзін, пра які я магу думаць, гэта проста "функцыя (бесперапыннага) часу", так што мая мадэль. Цудоўна, гэтая мадэль з лёгкасцю і вытанчанасцю апрацоўвае бесперапынны дэтэрмінаваных concurrency.

Было даволі складана рэалізаваць гэтую мадэль правільна і эфектыўна, але гэта яшчэ адна гісторыя.

932
23 июня '09 в 7:31 2009-06-23 07:31 адказ дадзены Conal 23 чэрвеня '09 у 07:31 2009-06-23 07:31

У чыста функцыянальным праграмаванні пабочных эфектаў няма. Для многіх тыпаў праграмнага забеспячэння (напрыклад, што-небудзь з узаемадзеяннем з карыстачом) пабочныя эфекты неабходныя на пэўным узроўні.

Адзін са спосабаў атрымаць пабочны эфект, як і пры захаванні функцыянальнага стылю, - выкарыстоўваць функцыянальнае рэактыўнае праграмаванне. Гэта камбінацыя функцыянальнага праграмавання і рэактыўнага праграмавання. (Артыкул у Вікіпедыі, пра якую вы звязаліся, адносіцца да апошняй.)

Асноўная ідэя рэактыўнага праграмавання заключаецца ў тым, што існуюць пэўныя тыпы дадзеных, якія ўяўляюць значэнне "з часам". Вылічэнні, якія ўключаюць гэтыя значэння з змяненнем часу, самі будуць мець значэння, якія змяняюцца з часам.

Напрыклад, вы можаце ўявіць каардынаты мышы як пару значэнняў з цэлым лікам па часе. Скажам, у нас было нешта накшталт гэтага (гэта псевдокод):

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

У любы момант часу x і y будуць мець каардынаты мышы. У адрозненне ад нереактивного праграмавання, нам трэба толькі зрабіць гэта прызначэнне адзін раз, а зменныя x і y будуць заставацца "абноўленымі" аўтаматычна. Вось чаму рэактыўнае праграмаванне і функцыянальнае праграмаванне працуюць так добра: рэактыўнае праграмаванне ліквідуе неабходнасць мутаваць зменныя, у той жа час дазваляючы вам многае рабіць з зменнымі мутацыямі.

border=0

Калі затым зрабіць некаторыя вылічэнні, заснаваныя на гэтым, выніковыя значэння таксама будуць значэннямі, якія змяняюцца з часам. напрыклад:

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

У гэтым прыкладзе minX заўсёды будзе на 16 менш, чым каардыната x паказальніка мышы. З дапамогай бібліятэк, здольных рэагаваць, вы маглі б сказаць нешта накшталт:

 rectangle(minX, minY, maxX, maxY) 

І акно 32x32 будзе намалявана вакол паказальніка мышы і будзе адсочваць яго ўсюды, дзе яно перамяшчаецца.

Вось даволі добрая артыкул аб функцыянальным рэактыўным праграмаванні .

740
22 июня '09 в 21:06 2009-06-22 21:06 адказ дадзены Laurence Gonsalves 22 чэрвеня '09 а 21:06 2009-06-22 21:06

Лёгкі спосаб дасягнуць першай інтуіцыі пра тое, што гэта такое, - гэта ўявіць, што ваша праграма - гэта электронная табліца, і ўсе вашы зменныя з'яўляюцца вочкамі. Калі якая-небудзь з вочак у электроннай табліцы зменіцца, усе вочкі, якія спасылаюцца на гэтую вочка, таксама мяняюцца. Гэта сапраўды гэтак жа з FRP. Цяпер уявіце, што некаторыя з вочак змяняюцца самі па сабе (дакладней, ўзятыя з навакольнага свету): у сітуацыі з графічным інтэрфейсам становішча мышы было б добрым прыкладам.

Гэта абавязкова прапусціць даволі шмат. Метафара даволі хутка ламаецца, калі вы карыстаецеся сістэму FRP. Па-першае, звычайна робяцца спробы мадэлявання дыскрэтных падзей (напрыклад, пстрычкі мышы). Я проста змяшчаю гэта тут, каб даць вам ўяўленне аб тым, як гэта падабаецца.

144
23 июня '09 в 17:52 2009-06-23 17:52 адказ дадзены Bob 23 чэрвеня '09 у 17:52 2009-06-23 17:52

Для мяне гэта прыкладна два розныя значэння сімвала = :

  • У матэматыцы x = sin(t) азначае, што x іншае імя для sin(t) . Такім чынам, запіс x + y - гэта тое ж самае, што і sin(t) + y . Функцыянальнае рэактыўнае праграмаванне падобна на матэматыку ў гэтых адносінах: калі вы пішаце x + y , ён вылічаецца з дапамогай любога значэння t ў момант яго выкарыстання.
  • У C-падобных мовах праграмавання (імператыўныя мовы) x = sin(t) - гэта прызначэнне: гэта азначае, што x захоўвае значэнне sin(t) , узятае падчас прызначэння.
132
25 мая '12 в 17:52 2012-05-25 17:52 адказ дадзены user712092 25 мая '12 у 17:52 2012-05-25 17:52

ОК, з даведачных ведаў і чытання старонкі Вікіпедыі, на якую вы паказалі, падобна, што рэактыўнае праграмаванне - гэта нешта накшталт апрацоўкі струменя дадзеных, але з адмысловымі знешнімі "стымуламі", які запускаецца набор вузлоў для запуску і выканання іх вылічэнняў.

Гэта вельмі добра падыходзіць для дызайну карыстацкага інтэрфейсу, напрыклад, калі дотык карыстацкага інтэрфейсу (напрыклад, кіраванне гучнасцю ў дадатку для прайгравання музыкі) можа спатрэбіцца абнавіць розныя элементы адлюстравання і фактычны аб'ём аўдыёвыхаду. Калі вы змяняеце том (скажам, паўзунок), які будзе адпавядаць змене значэння, звязанага з node ў арыентаваным графе.

Розныя вузлы, якія маюць рэбры з гэтага "значэння тома" node, будуць аўтаматычна запускацца, і любыя неабходныя вылічэнні і абнаўлення, натуральна, будуць пульсаваць праз прыкладанне. Дадатак "рэагуе" на карыстацкі стымул. Функцыянальнае рэактыўнае праграмаванне будзе проста увасабленнем гэтай ідэі на функцыянальным мове або, як правіла, у рамках парадыгмы функцыянальнага праграмавання.

Больш падрабязна пра "вылічэнні патоку дадзеных", знайдзіце час гэтае слова ў Вікіпедыі або выкарыстоўвайце сваю любімую пошукавую сістэму. Агульная ідэя такая: праграма ўяўляе сабой арыентаваны граф вузлоў, кожны з якіх выконвае некалькі простых вылічэнняў. Гэтыя вузлы злучаныя адзін з адным графічнымі спасылкамі, якія забяспечваюць выснову некаторых вузлоў на ўваходы іншых.

Калі a node запускае ці выконвае яго вылічэнні, вузлы, падлучаныя да яго выйсцяў, маюць свае адпаведныя ўваходы "спрацавалі" ці "адзначаны". Любы node, які мае ўсе ўваходы, якія запускаюцца / пазначаныя / даступныя аўтаматычна, спрацоўвае. Графік можа быць няяўнай ці відавочнай у залежнасці ад таго, як рэалізавана рэактыўнае праграмаванне.

Вузлы можна разглядаць як стральбу паралельна, але часта яны выконваюцца серыйна або з абмежаваным parallelism (напрыклад, можа быць некалькі патокаў, якія выконваюць іх). Вядомы прыклад: Manchester Dataflow Machine , які (IIRC) выкарыстаў пазначаную архітэктуру дадзеных для планавання выканання вузлоў у графе праз адно або некалькі выканання адзінкі. Вылічэнне патоку дадзеных даволі добра падыходзіць для сітуацый, у якіх ініцыявальныя вылічэнні асінхронна прыводзяць да ўзнікнення каскадаў вылічэнняў, працуюць лепш, чым спрабаваць, каб выкананне вызначалася гадзінамі (або гадзінамі).

Рэактыўнае праграмаванне імпартуе гэтую ідэю "каскаду выканання" і, падобна, думае аб праграме ў стылі патоку дадзеных, але пры ўмове, што некаторыя з вузлоў падлучаныя да "таму свету" і запускаюцца каскады выканання калі гэтыя сэнсарна-падобныя вузлы змяняюцца. Выкананне праграмы тады выглядала б як нешта падобнае на складаную рэфлекторную дугу. Праграма можа ці не можа быць у асноўным сядзячым паміж раздражняльнікамі або можа асядаць у асноўным сядзячым стане паміж стымуламі.

"Нереактивное" праграмаванне будзе праграмаваць з зусім іншым уяўленнем пра патоку выканання і суадносінах з вонкавымі ўваходамі. Верагодна, гэта будзе некалькі суб'ектыўна, так як у людзей, верагодна, паўстане спакуса сказаць што-небудзь, што адказвае на знешнія рэсурсы, "рэагуе" на іх. Але, гледзячы на ​​дух рэчы, праграма, якая опросает чаргу падзей з фіксаваным інтэрвалам і адпраўляе любыя падзеі, знойдзеныя ў функцыі (або патокі), менш рэактыўнасць (паколькі яна выкарыстоўваецца толькі для ўводу карыстальнікам з фіксаваным інтэрвалам). Зноў жа, гэта дух рэчы тут: можна ўявіць, што ўбудаванне апытання з хуткім інтэрвалам апытання ў сістэму на вельмі нізкім узроўні і праграмаванне рэактыўным спосабам па-над ёй.

71
22 июня '09 в 20:45 2009-06-22 20:45 адказ дадзены Thomas Kammeyer 22 чэрвеня '09 а 20:45 2009-06-22 20:45

Пасля чытання шматлікіх старонак аб FRP я, нарэшце, наткнуўся на гэты прасвету ліст аб FRP, ён, нарэшце, прымусіў мяне зразумець, што такое FRP.

Я цытую ніжэй Хайнриха Апфелмуса (аўтара рэактыўнага банана).

У чым сутнасць функцыянальнага рэактыўнага праграмавання?

Агульным адказам будзе тое, што "FRP - гэта апісанне апісання сістэмы ў тэрміны зменлівых ў часе функцый замест зменлівага стану", і што несумненна, не будзе памылкай. Гэта семантычная пункт гледжання. Але ў на маю думку, больш глыбокі, больш здавальняючы адказ вынікаючы чыста сінтаксічнага крытэру:

Сутнасць функцыянальнага рэактыўнага праграмавання заключаецца ў тым, каб паказаць дынамічнае паводзіны значэння цалкам падчас аб'явы.

Напрыклад, вазьміце прыклад лічыльніка: у вас ёсць дзве кнопкі з надпісам "Уверх" і "Уніз", якія могуць выкарыстоўвацца для павелічэння або памяншэння лічыльнік. Імператыўна, вы павінны спачатку назваць пачатковае значэнне і затым змяняць яго пры націску кнопкі; нешта накшталт гэтага:

  counter: = 0 - начальное значение on buttonUp = (счетчик: = счетчик + 1) - изменить его позже on buttonDown = (счетчик: = счетчик - 1) Код> 

Справа ў тым, што падчас абвяшчэння толькі пачатковае значэнне для лічыльніка паказана; дынамічнае паводзіны лічыльніка маецца на ўвазе ў астатняй часткі тэксту праграмы. Наадварот, функцыянальныя рэактыўнае праграмаванне вызначае ўсе дынамічнае паводзіны ў той час аб'явы, напрыклад:

  counter:: Behavior Int counter = accumulate ($) 0   (fmap (+1) eventUp`union` fmap (вычесть 1) eventDown) Код> 

Кожны раз, калі вы хочаце зразумець дынаміку лічыльніка, у вас ёсць толькі паглядзець на яго вызначэнне. Усё, што з ім можа здарыцца, будзе з'яўляюцца справа. Гэта вельмі моцна адрозніваецца ад калі наступныя дэкларацыі могуць дынамічнае паводзіны раней абвешчаных значэнняў.

Такім чынам, у маім разуменні праграма FRP ўяўляе сабой набор раўнанняў: 2019

65
31 янв. адказ дадзены jhegedus 31 студз. 2015-01-31 06:46 '15 у 06:46 2015/01/31 06:46

Адмова ад адказнасці: мой адказ знаходзіцца ў кантэксце rx.js - бібліятэкі "рэактыўнага праграмавання" для Javascript.

У функцыянальным праграмаванні замест паўтарэння кожнага элемента калекцыі вы ўжываеце функцыі больш высокага парадку (HoF) да самой калекцыі. Такім чынам, ідэя FRP заключаецца ў тым, што замест апрацоўкі кожнага асобнага падзеі стварыце паток падзей (рэалізаваны з дапамогай назіранага *) і замест гэтага ўжыеце HoF. Такім чынам, вы можаце візуалізаваць сістэму як патокі дадзеных, якія злучаюць выдаўцоў з падпісантамі.

Асноўныя перавагі выкарыстання назіраных:
i) ён абстрагуюцца стан ад вашага кода, напрыклад, калі вы хочаце, каб апрацоўшчык падзеі быў запушчаны толькі для кожнага n-га падзеі ці спыніў страляніну пасля першых "n" падзей або пачаў страляць толькі пасля першага "n" ', вы можаце проста выкарыстоўваць HoFs (фільтр, takeUntil, skip адпаведна) замест налады, абнаўлення і праверкі лічыльнікаў.
ii) он улучшает локальность кода - если у вас есть 5 разных обработчиков событий, изменяющих состояние компонента, вы можете объединить их наблюдаемые и определить один обработчик событий на объединенном наблюдаемом вместо этого, эффективно комбинируя 5 обработчиков событий в 1. Это делает его очень легко понять, какие события во всей системе могут повлиять на компонент, поскольку все это присутствует в одном обработчике.

  • Наблюдаемое - это двойственное значение Итерабельного.