Seija
首页
Travellings
登录
注册
首页
文章
Reflex介绍
这是一系列能让人们开始使用reflex进行编程的教程。 它假定您已经学会了Haskell语言,例如其中的`Applicative`和`Monad`类型类。如果你还没有,我通常会推荐[CIS194 course](https://www.seas.upenn.edu/~cis194/spring13/lectures.html)。我们一些人将这些讲座转发给我们当地的聚会小组,所以如果你喜欢讲座视频,可以看[这里](https://github.com/bfpg/cis194-yorgey-lectures)。[Haskell Book](http://haskellbook.com/)也是一本不错的书。 Stephen Blackheath和Anthony Jones有一本[Functional Reactive Programming](https://www.manning.com/books/functional-reactive-programming)的书我也强烈推荐它。他在FRP的说明和推广方面做的很好。它使用`sodium`库,他有许多语言的绑定,书中的例子大部分都是Java的。 ## 什么是函数响应式编程(FRP)? 在过去的几年里,人们对FRP产生了很大的兴趣,现在有很多不同的FRP含义在使用。我的想法是越接近原始的FRP想法的实现就越强大和有用。我们先来看一看FRP的定义。 FRP的原始定义有: * `Event`和`Behavior` 类型。 并且: * 明确的指称语义 * 支持连续时间 `Event`和`Behavior`是这个系统的核心。`Event`的值会在某个时间点改变,例如用户点击按钮,或者倒计时时间到了。`Behavior`在所有的时间点都有值,例如鼠标的位置或者用户是否有网站的管理员权限。`Behavior`是通过时间创建更改和查询,并且他们都是`Applicative`的实例所以我们可以组合他们。 与普通人的习惯相比,这会使状态非常不同,他非常强大我们很快就会看到。 我更喜欢的实现: * 有`Event`和`Behavior`类型。 * 有明确的指称语义 * 能够支持更高级的FRP,以便随时更改`Event`和`Behavior`。 * 已经提供了API来降低引入空间或时间泄漏的风险。 这些系统通过内置和加强版的observers,为您提供了可变状态的`first-class`值。 我们使用的实现提供的是离散时间的FRP而不是连续时间的FRP,这个差异就像数字和模拟电路一样。离散时间的FRP使用事件作为驱动电路的时钟,而连续时间的FRP则不是。这意味着使用连续时间的FRP我们可以操作采样和更新的频率,这在使用多媒体的时候十分方便。它还比离散时间的FRP系统有更简单的指称语义。 虽然这会导致我们在离散时间的FRP中无法表达一些东西。尽管如此我发现他还是非常好用的。如果出现了一个连续时间的FRP库我会非常乐意去看看,这样我就可以发现我错过了什么。 关于实现的另一个有趣的事情是,我更倾向于喜欢相分离的设计。API提供给用户的是一个描述FRP网络的数据结构,和它如何随着时间改变的逻辑。这样的话这个库将有效的编译成通过开关和寄存器实现的高效的图形。以及使其与所选语言的垃圾收集器很好地协作。这意味着有机会在具有相对稳定的面向用户的API的同时提高性能或减少系统的内存使用。 文档可能是目前这些系统最大的不足,这个系列教程,希望在这些方面有所帮助。 ## 什么是`reflex`? `reflex`库是FRP的一个实现,他满足上面列出的所有首选项。它的性能也非常高,并且他的可用性方面做的也很好。 虽然目前大家关注的焦点是通过GHCJS和`reflex-dom`来构建Web前端。但是其实也可以通过GHC来编译你的`reflex`代码。 也支持编写新的后端,所以其实你可以在其他地方使用它,只要那里有一个可变状态模型的需求。例如: * 命令行应用程序 * 服务器 * SDL应用 值得注意的是`reflex`其实可以扩展到连续时间的FRP,我的理解是没有紧迫的需求来推动这项工作。 我们稍后会看一下这个支持,但是现在我们将专注于使用`reflex`来创建Web前端,用于创建和操作DOM。`reflex`和`reflex-dom`和目前流行的方法有很大不同,在我继续之前我们有必要谈一下这些方法。 ## 什么是虚拟DOM? 在浏览器中,文档对象模型(DOM)是一个可变树,在树枝和树叶处具有可变状态。这对许多人来说听起来并不理想。搜索和修改也很慢。 为了解决这个问题,一些聪明的人发现,他们可以构建一个数据结构来模拟DOM - 虚拟或者说是影子DOM - 并对其进行操作。这样做的诀窍是使用高效的程序来找到DOM之间的差异并对其进行修补,以便您可以将虚拟DOM中的更改转换为实际DOM中的更改,同时最大限度地减少操作的工作量。 `react`库和许多其他框架都在使用这个想法,很多人都热衷于它。这看起来是一个实现的方法,这很好。如果你正在努力处理一个在树枝和叶子上具有可变状态的可变树,那么你会找到很多可行的解决方案。 有些人尝试使用更实用的方法,在DOM上工作就像使用纯函数一样: ``` Haskell DOM -> DOM ``` 问题在于它建立在DOM无状态的假设之上,这个假设是不正确的。我们可以在input框中看到DOM没有捕获到的状态,例如输入中的文本或者当前光标的位置。 这些库倾向于使用下面这两种方式处理input。 你可以使用本地状态,就像`react`一样。这意味着你有一个可变树,在树枝和树叶处有可变状态,但是树的类型和粒度与DOM的不同。 另一种方法是从DOM树中提取您感兴趣的所有状态,管理和更改它,然后在下次更新DOM树时使用它来更新状态。这为您提供了另一个可变树,在树枝和叶子上具有可变状态,您可以在事件循环中对DOM进行分层。 这可能是一个重要的全局对象,或者您可能能够将其范围更紧密地放在使用状态的位置。你可以看到像`redux`和`halogen`使用这样的方法。 我的主张是,一旦你对`reflex`感到满意: * 使用函数式的和一些工具,使您将能够在树枝和树叶上使用具有可变状态的可变树。 * 您将能够对虚拟DOM执行像对DOM一样的操作,但无需执行差异或修补步骤。 在Haskell社区中,我们定期听到使用非函数式编程语言跳到Haskell的人们,但是之后他们更喜欢他们之前的工作语言了。如果你正在使用其他一些流行的库和框架,那么会有一些风险发生,但如果你已经有足够的Haskell知识用于本系列,你可能已经接受并处理了这个风险。 ## 开始 安装`reflex`库的最简单方法是通过`reflex-platform`: > git clone https://github.com/reflex-frp/reflex-platform > cd reflex-platform > ./try-reflex 当然您应该确保阅读了`reflex-platform`的README中的操作系统兼容性说明(如果它们适用于您)。 `reflex`使用Nix进行项目配置,所以我们不必通过其他环节来设置GHCJS等等。`./try-reflex`会为你安装Nix和一些包的二进制缓存,这将为你节省很多时间(第一次会很慢)。 在大多数情况下,我们不需要知道任何Nix来使用它,因为reflex-platform附带了一些方便的shell脚本。 如果我们有一个基于cabal的项目,我们想用GHCJS编译,我们可以使用: ```Haskell cd my-cabal-project PATH_TO_REFLEX_PLATFORM/work-on ghcjs ./. cabal configure --ghcjs ``` 如果我们想用GHC编译它: ```Haskell cd my-cabal-project PATH_TO_REFLEX_PLATFORM/work-on ghc ./. cabal configure ``` 我们将在本系列的后续文章中介绍如何使用Nix做更多更好的事情。 如果您想测试这个设置和一些相关的工具,我们有一个[练习](/Haskell/Reflex/ReflexExercises)就是为了这个目的的。 ## 接下来 正如我所提到的,强大的FRP库的核心有两种主要类型:`Event`s和`Behavior`s。 [下一篇](/Haskell/Reflex/Event)将介绍`Event`s。
登录
登录
注册
最热文章
引擎中Template DSL的设计思考总结
10-19
ReaderT 设计模式
04-23
非主流引擎开发不出来 (n+1) : purescript侧结构设计
04-04
FRP系统的设计
03-17
非主流引擎开发不出来 (1) : 轻骨架
02-11
非主流引擎开发不出来 (0) : 引擎定位
12-09
Rust的ECS库specs
11-20
Haskell类型类高级扩展详细说明
05-31
CMake 速览
05-29
尼采导读:超人与永恒轮回
02-24
为什么elm的结构并不是最合理的?
02-20
React速览
02-20
尼采命运之爱
02-18
AspNetCore 速览
02-17
由Haskell和面向对象引出的关于抽象的思考
12-26
二进制文件压缩工具upx
12-24
Reflex介绍
12-17
Web的前端渲染和WebApi
12-16
前端FRP框架深度踩坑
12-16
Yesod - RESTful (11)
12-16
链接
github
gitee