Skip to content

Commit bbc6ef4

Browse files
author
Steve Krouse
committed
## Back at the FRP essay!
* TOC {: toc } The changes I'm comitting now were actually done this past Friday. It's not a ton of work but it wasn't pulling teeth - it was fun. And I'm excited enough about it that I actually made my girlfriend listen to me read it to her - she was a great sport. The langauge is a bit technical / high level. There's a lot I need to expound on / elaborate in there, and I imagine that some ambiguity in the essay are weak spots I need to explore more. Yesterday I had a lot of fun comparing and contrasting TodoMVC in Elm and Redux. I printed out the code for both on paper and wrote all over them. I have a lot of questions about the types of things in Redux that I'll have to investigate next. One idea I had is that to make the comparison more apples-to-apples, I could write TodoMVC in Redux but with the Elm Architecture - this is possible but not the reverse. However, that is a bunch of work considering how slow my Reflex/ghcjs feedback loop is. Another possible task is implementing focus on input elements, localstorage, and url hash get/set in Reflex to make them truly equal - but that's not really the point so it may be more work than it's worth. I only have two weeks before I have to submit to REBLS. I think I have enough for the paper in progress section, but I want to make it as best I can before that date. However, I also have work for Dark and First Round I should do this week - as well as taking some time off to spend with family that's around this month. It's a lot going on! ### Dark research I spent 3 hours this morning compiling lists of various interesting progrmming environments. What I'm most excited about is my list of classics that I've never played with: * Hypercard * squeak / etoys / morphicjs / pharo / http://gtoolkit.org/ * Labview * apl * Self * Forth * Prolog * Sketchpad * Matlab / simulink * Yahoo pipes As well as a few I keep haering about: * prograph * paxmsp and pure data vvvv * JetBrains MPS * emacs org mode * TLA+ / Alloy * Sonic Pi * R * https://www.blender.org/ * Godot engine * Qt * Chalktalk * http://mbeddr.com/ * http://openendedgroup.com/field/OverviewBanners2.html
1 parent 490b931 commit bbc6ef4

File tree

1 file changed

+21
-18
lines changed

1 file changed

+21
-18
lines changed

drafts/frp.md

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,45 @@ title: FRP
99

1010
## 1. Introduction
1111

12-
Explicit dependencies clarify which sections of code are independent to our current investigations, keeping the "effort needed to concieve or to understand a program ... not more than proportional to the program length" [Humble Programmer].
12+
When trying to understand a small piece of a large software project, explicit dependencies clarify which sections of code are independent to our current investigations, keeping the "effort needed to concieve or to understand a program ... not more than proportional to the program length" [Humble Programmer].
1313

14-
In pure functional programming, all terms explicitly list what they depend upon - as opposed to imperitive programming where terms can "be dependent on many, many different hidden mutable variables" [Out of the Tarpit].
14+
Explict data relationships is one of the benefits of functional programming, because all terms explicitly list what they depend upon. This contrasts with imperitive programming, where terms can "be dependent on many, many different hidden mutable variables" [Out of the Tarpit].
1515

16-
However, functional programming isn't immune to hidden dependencies:
16+
However, functional programming can simulate "hidden mutable variables" via an compound state value that it passes around as an extra parameter:
1717

18-
> There is in principle nothing to stop functional programs from passing a single extra parameter into and out of every single function in the entire system. If this extra parameter were a collection (compound value) of some kind then it could be used to simulate an arbitrarily large set of mutable variables. In effect this approach recreates a single pool of global variables — hence, even though referential transparency is maintained, ease of reasoning is lost (we still know that each function is dependent only upon its arguments, but one of them has become so large and contains irrelevant values that the benefit of this knowledge as an aid to understanding is almost nothing).
18+
> There is in principle nothing to stop functional programs from passing a single extra parameter into and out of every single function in the entire system. If this extra parameter were a collection (compound value) of some kind then it could be used to simulate an arbitrarily large set of mutable variables. In effect this approach recreates a single pool of global variables — hence, even though referential transparency is maintained, ease of reasoning is lost (we still know that each function is dependent only upon its arguments, but one of them has become so large and contains irrelevant values that the benefit of this knowledge as an aid to understanding is almost nothing). [Out of the Tarpit]
1919
20-
The popular Functional Reactive Elm Architecture suffers from this problem. I argue that the way to maintain explicit dependencies in Functional Reactive Programming is through cyclic and higher-order streams, as demonstrated by the Reflex framework.
20+
While this is considered an anti-pattern in many functional programming settings [TODO source needed], a variation on it has become the dominant architecture in Functional Reactive Programming. Originally concieved for the Elm programming langauge, The Elm Architecture has since inspired ReactJS's Redux, VueJS's Vuex, CycleJS's Onionify, among many other front-end state management libraries. [TODO source needed]
2121

22-
2. The Elm Architecture
22+
This paper contrasts the Elm Architecture with Haskell's Reflex, featuring higher-order streams and cyclic streams, with an eye towards idepedent comprehensibility through explicit data dependencies.
2323

24-
Elm is a pure functional language in the spirit of Haskell that compiles to JavaScript. It is an FRP-inspired langauge that only allows first-order and non-cyclic streams.
24+
## 2. The Elm Architecture
2525

26-
The Elm Architecture follows directly from the first-order, non-cyclic restrictions. Because streams cannot contain other streams, nor be cyclical, the only way to construct a user interface, which is inherently cyclical, is to have a single, large, language-supported cycle.
26+
Elm is a pure functional language in the spirit of Haskell. It compiles to JavaScript. It is an FRP-inspired langauge that only allows first-order and non-cyclic streams for reasons discussed in [TODO disease worse than cure?].
2727

28-
<iframe width="500" height="300" src="https://mermaidjs.github.io/mermaid-live-editor/#/view/eyJjb2RlIjoiXG5ncmFwaCBURFxuIFxucmVkdWNlci0tPnN0YXRlXG5zdGF0ZSAtLT4gdmlldyBcbnZpZXctLT58ZXZlbnR8cmVkdWNlclxuIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0" frameborder="0" allowfullscreen></iframe>
28+
The Elm Architecture follows directly from Elm's first-order, non-cyclic nature: because streams cannot contain other streams, nor be cyclic, the only way to construct user interfaces, which are inherently cyclical, is to have a single, large, language-supported cycle.
2929

30-
The Elm Architecture was built originally for use in Elm, but has since inspired ReactJS's Redux, VueJS's Vuex, CycleJS's Onionify, among many other front-end state management libraries.
30+
<iframe width="500" height="300" src="https://mermaidjs.github.io/mermaid-live-editor/#/view/eyJjb2RlIjoiXG5ncmFwaCBURFxuIFxucmVkdWNlci0tPiBzMihuZXcgc3RhdGUpXG5zMihuZXcgc3RhdGUpIC0tPiB2aWV3IFxudmlldy0tPnxldmVudCwgb2xkIHN0YXRlfHJlZHVjZXJcbiIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In19" frameborder="0" allowfullscreen></iframe>
3131

32-
Let's examine the architecture. The reducer is a function that takes the old state and an event, and returns a newly computed state.
32+
The core of this architecture is its a compound state value, which along with the reducer, which returns a new state in response to events, "simulate[s] an arbitrarily large set of mutable variables." [Tarpit]
3333

3434
```haskell
3535
reducer :: state -> event -> state
3636
```
3737

38-
The way the view sends events to the `reducer` differs between the frameworks. As we saw above, CycleJS derives event information *outside* the view, such as `const clicks = DOM.select('#counter-button').events('click')`. React and Elm generate events from *within* view, such as `<button onClick={this.handleClick()}>` or `button [ onClick Increment ]`, respectively.
38+
The view is a pure function of state.
3939

40-
Additionally, these frameworks sometimes wrap events in semantic labels called "actions" or "messages". For example, above the `onClick` event is labeled as the `Increment` action. This will become clearer in the Elm example below.
40+
The way the view sends events to the `reducer` differs between frameworks. CycleJS derives event information *outside* the view, such as `const clicks = DOM.select('#counter-button').events('click')`. React/Redux and Elm generate events from *within* view, such as `<button onClick={this.handleClick()}>` or `button [ onClick Increment ]`, respectively.
4141

42-
In the Elm Architecture, we are explicit about the initial value of state, how the state determines the view, and how various events effect the state. This is a huge improvement over the Imperative Button above. For one, it gives us serializable state, which we can use for hot-swapping and time travel debugging!
42+
Additionally, these frameworks sometimes wrap events in semantic labels called "actions" or "messages". For example, an `onClick` event can be labeled as the `Increment` action. This will become clearer in the Elm example below.
4343

44-
However, let's examine the Elm Architecture from a modular comprehensibility point of view.
44+
Just like in imperitive programming, the Elm Architecture is explict only about the *initial* values of states.
4545

4646
Any message can modify any state. In the reducer, called `update` in [Elm ToDoMVC](https://github.com/evancz/elm-todomvc/blob/master/Todo.elm), the `Add` message triggers an update of three different pieces of state:
4747

4848
![image](https://user-images.githubusercontent.com/2288939/42886488-ab1c24c4-8a71-11e8-92f5-13dc2f282ad4.png)
4949

50-
This means that you can't modularly gain a complete understanding of any piece of state. You have to look through *all* the messages for any piece of state, which may be spread across many files.
50+
This means that you can't modularly gain a complete understanding of any piece of state. You have to look through *all* messages to see if and how it affects the state in question.
5151

5252
There's also a subtler way this undermines explicit dependencies: each piece of state can be modified in terms of *any other piece of state*. There's no explicit isolation between independent states.
5353

@@ -57,6 +57,10 @@ Additionally, any view element can emit any message. Again from [Elm ToDoMVC](ht
5757

5858
If were looking to understand a single piece of state, were not much better off than with an entirely imperative framework: we still have to read more-or-less the whole application even if we wish only to comprehend only a small piece.
5959

60+
## 3. Reflex
61+
62+
The Reflex library was built for Haskell web development via ghcjs. It features higher-order and cyclic streams.
63+
6064
## ToDo
6165

6266
* maybe reverse the order of the introduction
@@ -65,8 +69,7 @@ If we’re looking to understand a single piece of state, we’re not much bette
6569
* inversion of control (http://degoes.net/articles/destroy-all-ifs)
6670
* explicit in the math formula sense
6771
* the elm architecture section
68-
* edit this section a lot
69-
* the elm architecture simulates imperitive, von-neuman, one word at a time architecture in a functional setting
72+
* maybe simulates von-neuman, one word at a time
7073
* argue that it's difficult to mechanically convert to explicit form
7174
* argue the treatment is *not* worse than the disease
7275
* This design decision was made consciously in Elm to decrease coupling. [3]

0 commit comments

Comments
 (0)