it-swarm.com.ru

Что такое (функциональное) реактивное программирование?

Я прочитал статью в Википедии о реактивное программирование . Я также прочитал небольшую статью о функционально-реактивное программирование . Описания довольно абстрактны.

  1. Что означает функционально-реактивное программирование (FRP) на практике?
  2. Из чего состоит реактивное программирование (в отличие от нереактивного программирования?)?

Я имею опыт работы с языками императив/OO, так что объяснение, которое относится к этой парадигме, будет оценено.

1149
JtR

Если вы хотите почувствовать FRP, вы можете начать со старого Fran tutorial 1998 года, в котором есть анимированные иллюстрации. Для статей начните с Функциональная реактивная анимация , а затем перейдите по ссылкам на ссылку публикаций на моей домашней странице и - FRP ссылка на Haskell wiki .

Лично мне нравится думать о том, что означает FRP , прежде чем рассматривать, как это может быть реализовано. (Код без спецификации - это ответ без вопросов и, следовательно, "даже не неправильный".) Поэтому я не описываю FRP в терминах представления/реализации, как это делает Томас К. в другом ответе (графики, узлы, ребра, выстрелы, выполнение, так далее). Существует много возможных стилей реализации, но ни одна из реализаций не говорит, что такое FRP .

Я действительно резонирую с простым описанием Лоуренса Дж., Что FRP о "типах данных, которые представляют значение" с течением времени "". Обычное императивное программирование фиксирует эти динамические значения только косвенно, через состояние и мутации. Полная история (прошлое, настоящее, будущее) не имеет представления первого класса. Более того, только дискретно развивающиеся значения могут быть (косвенно) захвачены, поскольку императивная парадигма временно дискретна. Напротив, FRP фиксирует эти изменяющиеся значения напрямую и не имеет проблем с непрерывно развивающиеся ценности.

FRP также необычен тем, что он происходит одновременно, не сталкиваясь с гнездом теоретических и прагматических крыс, которое изводит императивный параллелизм. Семантически, параллелизм FRP является мелкозернистым , детерминированным и непрерывна . (Я говорю о смысле, а не о реализации. Реализация может включать или не включать параллелизм или параллелизм.) Семантическая определенность очень важна для рассуждений, как строгих, так и неформальных. В то время как параллелизм добавляет огромную сложность императивному программированию (из-за недетерминированного чередования), он не требует усилий в FRP.

Итак, что такое FRP? Вы могли бы изобрести это сами. Начните с этих идей:

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

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

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

  • Чтобы придумать композиционный словарь, из которого можно построить все виды поведения и события, поиграйте с некоторыми примерами. Продолжайте разбивать на части, которые являются более общими/простыми.

  • Чтобы вы знали, что находитесь на твердой почве, дайте всей модели композиционную основу, используя технику денотационной семантики, которая просто означает, что (а) каждому типу соответствует соответствующий простой и точный математический тип "значений", и ( б) каждый примитив и оператор имеют простое и точное значение в зависимости от значений составляющих. Никогда, никогда не включайте соображения реализации в ваш процесс исследования. Если это описание для вас бессмысленно, обратитесь к (a) Денотационный дизайн с морфизмами классов типов, (b) двухтактное функциональное реактивное программирование (игнорирование битов реализации) и (c) Денотационная семантика страница викибук на Haskell . Помните, что денотационная семантика состоит из двух частей, от двух ее основателей, Кристофера Стрейчи и Даны Скотт: более простая и полезная часть Стрейчи и более сложная и менее полезная (для разработки программного обеспечения) часть Скотта.

Если вы будете придерживаться этих принципов, я ожидаю, что вы получите что-то более или менее в духе FRP.

Где я взял эти принципы? В разработке программного обеспечения я всегда задаю один и тот же вопрос: "что это значит?". Семантика денотации дала мне точную основу для этого вопроса, которая соответствует моей эстетике (в отличие от операционной или аксиоматической семантики, обе из которых оставляют меня неудовлетворенным). Поэтому я спросил себя, что такое поведение? Вскоре я понял, что дискретно во времени природа императивных вычислений является приспособлением к определенному стилю машины , а не естественным описанием самого поведения. Самое простое точное описание поведения, которое я могу придумать, это просто "функция (непрерывного) времени", так что это моя модель. Восхитительно, эта модель обрабатывает непрерывный, детерминированный параллелизм с легкостью и изяществом.

Реализовать эту модель правильно и эффективно было довольно сложно, но это уже другая история.

932
Conal

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

Один из способов получить побочный эффект, такой как поведение, при сохранении функционального стиля, - это использовать функциональное реактивное программирование. Это сочетание функционального программирования и реактивного программирования. (Статья в Википедии, на которую вы ссылаетесь, посвящена последнему.)

Основная идея реактивного программирования заключается в том, что существуют определенные типы данных, которые представляют значение "со временем". Вычисления, которые включают эти изменяющиеся во времени значения, сами будут иметь значения, которые изменяются со временем.

Например, вы можете представить координаты мыши в виде пары целочисленных значений по времени. Допустим, у нас было что-то вроде (это псевдокод):

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

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

Если затем мы сделаем некоторые вычисления, основанные на этом, результирующие значения также будут значениями, которые меняются со временем. Например:

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

В этом примере minX всегда будет на 16 меньше, чем координата x указателя мыши. С библиотеками, поддерживающими реагирование, вы можете сказать что-то вроде:

rectangle(minX, minY, maxX, maxY)

А вокруг указателя мыши будет нарисован прямоугольник размером 32x32, который будет отслеживать его перемещение.

Вот довольно неплохо статья о функционально-реактивном программировании .

740
Laurence Gonsalves

Самый простой способ понять, что это такое - представить, что ваша программа - это электронная таблица, а все ваши переменные - это ячейки. Если какая-либо из ячеек в электронной таблице изменится, все ячейки, которые ссылаются на эту ячейку, также изменятся. То же самое с FRP. Теперь представьте, что некоторые ячейки изменяются сами по себе (или, скорее, взяты из внешнего мира): в ситуации с графическим интерфейсом, расположение мыши было бы хорошим примером.

Это обязательно пропускает довольно много. Метафора разрушается довольно быстро, когда вы на самом деле используете систему FRP. Например, обычно предпринимаются попытки смоделировать отдельные события (например, нажатие мыши). Я просто помещаю это здесь, чтобы дать вам представление о том, на что это похоже.

144
Bob

Для меня это примерно 2 разных значения символа =:

  1. В математике x = sin(t) означает, что x является другое имя для sin(t). Таким образом, написание x + y - это то же самое, что и sin(t) + y. Функционально-реактивное программирование в этом отношении похоже на математику: если вы пишете x + y, оно вычисляется с любым значением t во время его использования.
  2. В C-подобных языках программирования (императивных языках) x = sin(t) является присваиванием: это означает, что x хранит значениеsin(t), полученное во время назначения.
131
user712092

Итак, из базовых знаний и чтения страницы Википедии, на которую вы указали, кажется, что реактивное программирование - это что-то вроде вычисления потока данных, но с определенными внешними "стимулами", запускающими набор узлов для выполнения и выполнения их вычислений.

Это довольно хорошо подходит для дизайна пользовательского интерфейса, например, когда при касании элемента управления пользовательского интерфейса (скажем, элемента управления громкостью в приложении для воспроизведения музыки) может потребоваться обновить различные элементы отображения и фактическую громкость звука. Когда вы изменяете объем (скажем, ползунок), который соответствует изменению значения, связанного с узлом в ориентированном графе.

Различные узлы, имеющие ребра от этого узла "значение объема", будут автоматически запускаться, и любые необходимые вычисления и обновления будут естественным образом распространяться через приложение. Приложение "реагирует" на пользовательский стимул. Функционально-реактивное программирование было бы просто реализацией этой идеи на функциональном языке или вообще в рамках парадигмы функционального программирования.

Для получения дополнительной информации о "вычислениях потока данных", найдите эти два слова в Википедии или используя вашу любимую поисковую систему. Общая идея такова: программа представляет собой ориентированный граф узлов, каждый из которых выполняет простое вычисление. Эти узлы связаны друг с другом графическими ссылками, которые обеспечивают выходы некоторых узлов на входы других.

Когда узел запускает или выполняет свои вычисления, узлы, подключенные к его выходам, имеют свои соответствующие входы "сработали" или "помечены". Любой узел, имеющий все входы, сработавшие/помеченные/доступные, автоматически срабатывает. График может быть неявным или явным в зависимости от того, как именно реализовано реактивное программирование.

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

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

"нереактивное" программирование - это программирование с совершенно другим представлением о потоке выполнения и взаимосвязи с внешними входами. Вероятно, это будет несколько субъективно, поскольку люди, скорее всего, будут испытывать искушение сказать что-либо, что реагирует на внешние воздействия, "реагирует" на них. Но, если смотреть на это суть, программа, которая опрашивает очередь событий с фиксированным интервалом и отправляет любые события, найденные функциям (или потокам), менее реактивна (потому что она обслуживает ввод пользователя только с фиксированным интервалом). Опять же, в этом заключается суть: можно представить реализацию опроса с быстрым интервалом опроса в системе на очень низком уровне и программировать реагирующим образом поверх нее.

71
Thomas Kammeyer

Прочитав много страниц о FRP, я наконец-то наткнулся на этот поучительный текст о FRP, и, наконец, я понял, что такое FRP на самом деле.

Я цитирую ниже Генриха Апфельма (автора реактивного банана).

В чем суть функционально-реактивного программирования?

Распространенным ответом будет то, что "FRP - это все, что описывает систему в терминах изменяющихся во времени функций вместо изменяемого состояния", и это, безусловно, не будет ошибкой. Это семантическая точка зрения. Но, на мой взгляд, более глубокий, более удовлетворительный ответ дает следующий чисто синтаксический критерий:

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

Например, возьмем пример счетчика: у вас есть две кнопки с метками "Вверх" и "Вниз", которые можно использовать для увеличения или уменьшения счетчика. Обязательно, вы должны сначала указать начальное значение, а затем изменить его при каждом нажатии кнопки; что-то вроде этого:

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

Дело в том, что на момент объявления указывается только начальное значение счетчика; динамическое поведение счетчика подразумевается в остальной части текста программы. Напротив, функциональное реактивное программирование задает все динамическое поведение во время объявления, как это:

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

Всякий раз, когда вы хотите понять динамику счетчика, вам нужно только взглянуть на его определение. Все, что может случиться с ним, появится с правой стороны. Это очень сильно отличается от императивного подхода, при котором последующие объявления могут изменить динамическое поведение ранее объявленных значений.

Итак, в моем понимании программа FRP представляет собой набор уравнений: enter image description here

j является дискретным: 1,2,3,4 ...

f зависит от t, так что это включает в себя возможность моделировать внешние стимулы

все состояние программы заключено в переменные x_i

Библиотека FRP заботится о времени выполнения, другими словами, принимая j к j+1.

Я объясню эти уравнения более подробно в это видео.

EDIT:

Примерно через 2 года после первоначального ответа, недавно я пришел к выводу, что реализации FRP имеют еще один важный аспект. Они должны (и обычно делают) решить важную практическую проблему: аннулирование кэша .

Уравнения для x_i- описывают граф зависимостей. Когда некоторые из x_i изменяются во время j, тогда не все другие значения x_i' в j+1 необходимо обновлять, поэтому не все пересчеты необходимо пересчитывать, потому что некоторые x_i' могут быть независимыми от x_i.

Кроме того, x_i-, которые действительно изменяются, могут постепенно обновляться. Например, давайте рассмотрим операцию отображения f=g.map(_+1) в Scala, где f и g являются List из Ints. Здесь f соответствует x_i(t_j), а g - x_j(t_j). Теперь, если я добавлю элемент к g, тогда будет бесполезно выполнять операцию map для всех элементов в g. Некоторые реализации FRP (например, reflex-frp ) направлены на решение этой проблемы. Эта проблема также известна как дополнительные вычисления.

Другими словами, поведение (x_i-) в FRP можно рассматривать как вычисления с кэшированием. Задача механизма FRP - эффективно аннулировать и повторно вычислить эти кеши (x_i- s), если некоторые из f_i- действительно изменяются.

65
jhegedus

Отказ от ответственности: мой ответ в контексте rx.js - библиотеки "реактивного программирования" для Javascript.

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

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

  • Observable - это двойственное от Iterable.

Итерируемый - это лениво потребляемая последовательность - каждый элемент извлекается итератором всякий раз, когда он хочет его использовать, и, следовательно, перечисление управляется потребителем.

Наблюдаемая - это лениво созданная последовательность - каждый элемент передается наблюдателю всякий раз, когда он добавляется в последовательность, и, следовательно, перечисление управляется производителем.

29
tldr

Статья Просто эффективная функциональная реактивность Конала Эллиота ( прямой PDF , 233 КБ) представляет собой довольно хорошее введение. Соответствующая библиотека также работает.

Теперь этот документ заменен другим документом, двухтактное функциональное реактивное программирование ( прямой PDF , 286 КБ).

29
scvalex

Чувак, это чертовски блестящая идея! Почему я не узнал об этом еще в 1998 году? В любом случае, вот моя интерпретация учебника Fran . Предложения приветствуются, я думаю о запуске игрового движка, основанного на этом.

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()

Короче говоря: если каждый компонент можно рассматривать как число, вся система может рассматриваться как математическое уравнение, верно?

18
Dan Ross

Книга Пола Гудака, Школа выражений на Хаскелле , является не только прекрасным введением в Хаскель, но и проводит достаточно много времени на FRP. Если вы новичок в FRP, я настоятельно рекомендую вам понять, как работает FRP.

Существует также то, что выглядит как новая переписка этой книги (выпущена в 2011 году, обновлена ​​в 2014 году) Школа музыки Хаскелла .

14
Curt J. Sampson

Согласно предыдущим ответам, кажется, что математически мы просто мыслим в более высоком порядке. Вместо того, чтобы думать о значении x, имеющем тип X, мы думаем о функции x: TX, где T - это тип времени, будь то натуральные числа, целые числа или континуум. Теперь, когда мы пишем y: = x + 1 на языке программирования, мы фактически имеем в виду уравнение y (t =) = x (t) + 1.

10
Yuning

Действует как электронная таблица, как отмечено. Обычно основано на фреймворке, управляемом событиями.

Как и во всех "парадигмах", его новизна спорна.

Исходя из моего опыта распределенных потоковых сетей актеров, он может легко стать жертвой общей проблемы согласованности состояний в сети узлов, т. Е. Вы получите много колебаний и попадание в странные циклы.

Этого трудно избежать, поскольку некоторые семантики подразумевают референциальные циклы или широковещание, и могут быть довольно хаотичными, поскольку сеть действующих лиц сходится (или нет) в каком-то непредсказуемом состоянии.

Точно так же некоторые состояния могут быть не достигнуты, несмотря на то, что они имеют четко определенные ребра, поскольку глобальное состояние отклоняется от решения. 2 + 2 может или не может быть 4 в зависимости от того, когда 2 стали 2, и остались ли они таким образом. Таблицы имеют синхронные часы и обнаружение петель. Распределенные актеры обычно этого не делают.

Все хорошо, весело :).

9
emperorz

Я нашел это хорошее видео на subreddit Clojure о FRP. Это довольно легко понять, даже если вы не знаете Clojure.

Вот видео: http://www.youtube.com/watch?v=nket0K1RXU4

Вот источник, на который ссылается видео во 2-й половине: https://github.com/Cicayda/yolk-examples/blob/master/src/yolk_examples/client/autocomplete.cljs

8
Daniel Kaplan

Эта статья от Андре Штальца - лучшее и ясное объяснение, которое я когда-либо видел.

Некоторые цитаты из статьи:

Реактивное программирование - это программирование с асинхронными потоками данных.

Кроме того, вам предоставляется удивительный набор функций для объединения, создания и фильтрации любого из этих потоков.

Вот пример фантастических диаграмм, которые являются частью статьи:

Click event stream diagram

7
GreenGiant

Речь идет о математических преобразованиях данных во времени (или игнорировании времени).

В коде это означает функциональную чистоту и декларативное программирование.

Государственные ошибки - огромная проблема в стандартной императивной парадигме. Различные биты кода могут изменять некоторые общие состояния в разное "время" выполнения программ. С этим трудно иметь дело.

В FRP вы описываете (как в декларативном программировании), как данные преобразуются из одного состояния в другое и что его вызывает. Это позволяет вам игнорировать время, потому что ваша функция просто реагирует на свои входные данные и использует их текущие значения для создания нового. Это означает, что состояние содержится в графе (или дереве) узлов преобразования и является функционально чистым.

Это значительно снижает сложность и время отладки.

Подумайте о разнице между A = B + C в математике и A = B + C в программе. В математике вы описываете отношения, которые никогда не изменятся. В программе говорится, что "Прямо сейчас" A - это B + C. Но следующая команда может быть B ++, в этом случае A не равен B + C. В математическом или декларативном программировании A всегда будет равно B + C, независимо от того, в какой момент времени вы спрашиваете.

Таким образом, устраняя сложности общего состояния и изменяя значения с течением времени. Ваша программа гораздо проще рассуждать.

EventStream - это EventStream + некоторая функция преобразования.

Поведение - это EventStream + некоторое значение в памяти.

Когда событие запускается, значение обновляется с помощью функции преобразования. Это значение сохраняется в памяти поведений.

Поведения могут быть составлены для создания новых моделей поведения, которые трансформируют N других моделей поведения. Это составленное значение будет пересчитано как срабатывание входных событий (поведения).

"Поскольку наблюдатели не имеют состояния, нам часто требуется несколько из них для имитации конечного автомата, как в примере перетаскивания. Мы должны сохранить состояние, в котором он доступен для всех задействованных наблюдателей, например, в переменной path выше".

Цитата из - Устаревший шаблон наблюдателя http://infoscience.epfl.ch/record/148043/files/DeprecatingObserversTR2010.pdf

5
Jay Shepherd

Краткое и четкое объяснение о реактивном программировании появляется в Cyclejs - Реактивное программирование , в нем используются простые и наглядные примеры.

[Module/Component/object] является реактивным , что означает, что он полностью отвечает за управление своим собственным состоянием, реагируя на внешние события.

В чем выгода этого подхода? Это Инверсия Контроля , главным образом потому, что [модуль/Компонент/объект] отвечает за себя, улучшая инкапсуляцию с использованием частных методов по сравнению с открытыми.

Это хорошая точка запуска, а не полный источник знаний. Оттуда вы можете перейти к более сложным и глубоким документам.

2
pdorgambide

FRP представляет собой комбинацию функционального программирования (парадигма программирования, основанная на идее, что все является функцией) и парадигмы реактивного программирования (основанная на идее, что все является потоком (философия наблюдателя и наблюдаемого)). Это должно быть лучшим из миров.

Посмотрите на статью Андреа Штальца о реактивном программировании.

0
kg11

Проверьте Rx, Reactive Extensions для .NET. Они указывают, что с IEnumerable вы в основном "вытягиваете" из потока. Запросы Linq по IQueryable/IEnumerable представляют собой операции над множествами, которые "высасывают" результаты из набора. Но с теми же операторами над IObservable вы можете писать запросы Linq, которые "реагируют".

Например, вы можете написать запрос Linq наподобие (из m в MyObservableSetOfMouseMovements, где m.X <100 и m.Y <100 выберите новую точку (m.X, m.Y)).

и с расширениями Rx, вот и все: у вас есть код пользовательского интерфейса, который реагирует на входящий поток движений мыши и рисует, когда вы находитесь в поле 100 100 ...

0
Sentinel