Functional programming 什么是(功能性)反应式编程?

Functional programming 什么是(功能性)反应式编程?,functional-programming,terminology,reactive-programming,frp,Functional Programming,Terminology,Reactive Programming,Frp,我已经读了维基百科上的文章。我也读过关于这个问题的小文章。这些描述相当抽象 功能反应式编程(FRP)在实践中意味着什么 反应式编程(相对于非反应式编程?)由什么组成 我的背景是命令式/OO语言,因此,如果能解释一下这个范例,我将不胜感激。好的,从背景知识和您所指的维基百科页面来看,反应式编程似乎有点像数据流计算,但有特定的外部“刺激”触发一组节点激发并执行其计算 这非常适合UI设计,例如,触摸用户界面控件(例如,音乐播放应用程序上的音量控件)可能需要更新各种显示项目和音频输出的实际音量。当修改体

我已经读了维基百科上的文章。我也读过关于这个问题的小文章。这些描述相当抽象

  • 功能反应式编程(FRP)在实践中意味着什么
  • 反应式编程(相对于非反应式编程?)由什么组成
    我的背景是命令式/OO语言,因此,如果能解释一下这个范例,我将不胜感激。

    好的,从背景知识和您所指的维基百科页面来看,反应式编程似乎有点像数据流计算,但有特定的外部“刺激”触发一组节点激发并执行其计算

    这非常适合UI设计,例如,触摸用户界面控件(例如,音乐播放应用程序上的音量控件)可能需要更新各种显示项目和音频输出的实际音量。当修改体积(比如滑块)时,该体积对应于修改与有向图中的节点关联的值

    从“体积值”节点具有边缘的各种节点将自动触发,任何必要的计算和更新都会自然地在应用程序中波动。应用程序对用户刺激作出“反应”。函数式反应式编程只是在函数式语言中,或者通常在函数式编程范式中实现这一思想

    有关“数据流计算”的更多信息,请在Wikipedia或使用您喜爱的搜索引擎搜索这两个词。其基本思想是:程序是一个节点的有向图,每个节点执行一些简单的计算。这些节点通过图形链接相互连接,图形链接将一些节点的输出提供给其他节点的输入

    当节点触发或执行其计算时,连接到其输出的节点将其相应的输入“触发”或“标记”。任何具有所有触发/标记/可用输入的节点都会自动激发。该图可能是隐式的,也可能是显式的,具体取决于反应式编程的实现方式

    节点可以被看作是并行启动的,但它们通常是串行执行的,或者并行性有限(例如,可能有几个线程执行它们)。一个著名的例子是,它(IIRC)使用标记数据体系结构通过一个或多个执行单元来调度图中节点的执行。数据流计算非常适合于异步触发计算从而产生计算级联的情况,而不是试图让执行由一个或多个时钟控制

    反应式编程引入了这种“执行级联”的思想,似乎以一种类似数据流的方式来思考程序,但附带的条件是,一些节点连接到“外部世界”,当这些类似感觉的节点发生变化时,会触发执行级联。然后,程序执行看起来就像一个复杂的反射弧。程序在刺激之间可能基本上是固定的,也可能不是固定的,或者可能在刺激之间进入基本上是固定的状态

    “非反应式”编程将是对执行流程以及与外部输入的关系的一种完全不同的看法。这可能有点主观,因为人们可能会说任何对外部输入有反应的话。但从本质上看,以固定时间间隔轮询事件队列并将发现的任何事件分派给函数(或线程)的程序反应性较小(因为它只以固定时间间隔关注用户输入)。同样,这也是本文的精神所在:我们可以想象将具有快速轮询间隔的轮询实现放在一个非常低级别的系统中,并以一种反应式的方式进行编程。

    Conal Elliott的论文(,233KB)是一个相当好的介绍。相应的库也可以工作


    这篇论文现在被另一篇论文(,286KB)取代。

    在纯函数式编程中,没有副作用。对于许多类型的软件(例如,任何与用户交互的软件),副作用在某种程度上是必要的

    在保持函数式风格的同时获得类似副作用的行为的一种方法是使用函数式反应式编程。这是函数式编程和反应式编程的结合。(你链接到的维基百科文章是关于后者的。)

    反应式编程背后的基本思想是,某些数据类型表示“随时间变化”的值。涉及这些随时间变化的值的计算本身将具有随时间变化的值

    例如,您可以将鼠标坐标表示为一对随时间变化的整数值。假设我们有这样的东西(这是伪代码):

    在本例中,
    minX
    始终比鼠标指针的x坐标小16。使用反应式感知库,您可以说:

    rectangle(minX, minY, maxX, maxY)
    
    鼠标指针周围会画一个32x32的框,它会跟踪鼠标指针移动到的任何地方


    这是一个很好的例子。

    如果你想了解FRP,你可以从1998年的老款开始,它有动画插图。对于论文,请从我的主页上的出版物链接和

    就我个人而言,在讨论如何实施FRP之前,我喜欢思考FRP的含义。 (没有规范的代码是没有问题的答案,因此“甚至没有错”。) 因此,我不会像Thomas K在另一个答案(图、节点、边、触发、执行等)中那样用表示/实现术语来描述FRP。 有许多可能的实现样式,但没有实现说明FRP是什么

    我确实与Laurence G关于FRP是“数据类型”的简单描述产生共鸣
    minX = x - 16;
    minY = y - 16;
    maxX = x + 16;
    maxY = y + 16;
    
    rectangle(minX, minY, maxX, maxY)
    
    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()
    
    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)