Skip to content

Commit 1e2d490

Browse files
author
Steve Krouse
committed
continue dctp
1 parent aa9c9d0 commit 1e2d490

File tree

1 file changed

+97
-40
lines changed

1 file changed

+97
-40
lines changed

drafts/dctp.md

Lines changed: 97 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,44 @@ Then someone (I forget who - if this is you, THANK YOU!!!) suggested I listen to
3131

3232
Now I am cursed to be one of those condescending assholes, a Conal zombie, doomed to roam the land, pleading other to "go back and read Conal", while knowing full well how hard it will be for them to see the light. This essay is how I hope to give you my disease.
3333

34-
## The Curse of Coining a Programming Paradigm
34+
## DCTP & Denotational
35+
36+
### The Curse of Coining a Programming Paradigm
3537

3638
When a programming language designer defines a word in their language, that's the end of the story. But when a programming language designer coins a phrase in English, that's only the beginning of their ordeal. Alan Kay coined the phrase "object-oriented programming" (OOP) in the 70s, but OOP took on a life of its own, [which has caused much confusion and heartache to its creator](http://wiki.c2.com/?AlanKaysDefinitionOfObjectOriented).
3739

3840
Functional reactive programming (FRP) has [a similarly confused and contested etymology](https://medium.com/@andrestaltz/why-i-cannot-say-frp-but-i-just-did-d5ffaa23973b). In the 90s, Conal Elliott pioneered a new software paradigm for programming interactive animations and dubbed it "Functional Reactive Programming" (FRP). Like Kay, Elliott then watched others use his term to describe things totally opposed to his original vision. Conal eventually conceded defeat. Like OOP, FRP now is a bastardized term that refers to work *inspired* by the "original FRP." Conal has retreated to coining a new, less-sexy (maybe on purpose?) phrase to describe his original vision: Denotative Continuous Time Programming (DCTP). From here on out I will use DCTP to refer to "original FRP."
3941

42+
### Denotational Programming
43+
44+
Aren't spreadsheets wonderful? A key to their success is that there is no control flow, no sequencing of instructions. Only data flow.
45+
46+
In [What's Functional Programming All About?](http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbout.html), Li Hayoi explains: "The core of Functional Programming is thinking about data-flow rather than control-flow." He demostrates this beautifully by converting a stateful imperitive tiramisu recipe to a dataflow diagram:
47+
48+
![](https://user-images.githubusercontent.com/2288939/51426743-e7fc2400-1be6-11e9-9aa6-1c45d3c8f83e.png)
49+
50+
[TODO]
51+
52+
In [The Next 700 Programming Languages](https://www.cs.cmu.edu/~crary/819-f09/Landin66.pdf), Peter Landin calls such languages "denotative":
53+
54+
> (a) each expression has a nesting subexpression structure, (b) each subexpression
55+
denotes something (usually a number, truth value ornumerical function), (c) the thing an expression denotes, i.e., its "value", depends only on the values of its subexpressions, not on other properties of them.
56+
57+
In other words "denotative" languages contain no statements, but only nested mathmatical expressions, where each expression *denotes* (can be model by) some mathmatical object.
58+
59+
Denotational programming has a number of benefits:
60+
61+
1. **Equational reasoning**. In denotational programming, the equal sign (=) means what it does in a mathematics textbook: we can replace instances of the left with the expression to the right or vice-a-versa.
62+
2. **Definitional reasoning**. We can *fully* understand an expression by its subexpressions, and their subexpressions, recursively. There are no spooky action-at-a-distance side-effects that can manipulate things from afar. In this way, we don't have to read the entire codebase to understand all the places our state could be manipulated.
63+
3. **Modularity & Composibility**. TODO
64+
65+
I will follow Landin and [Elliott](http://conal.net/blog/posts/is-haskell-a-purely-functional-language) in using the phrase "denotational" instead of "functional", and "imperitive" to describe its opposite.
66+
4067
## Continuity
4168

4269
The [inspiration for DCTP came in the form of a question from John Reynolds](http://conal.net/blog/posts/early-inspirations-and-new-directions-in-functional-reactive-programming). It roughly amounted to:
4370

44-
> What would programming look like if time were continuous?
71+
> What would it be like to program in continuous time?
4572
4673
This is a wonderful question, but it's hard to answer it directly, partly because time is hard to visualize. Let's come at this via a slightly different question and then circle back to time:
4774

@@ -61,7 +88,7 @@ SVGs retain all the relevant info until the very last moment when the computer f
6188

6289
#### What is a graphic?
6390

64-
Let's get a bit more mathematical[[1](#1)] with our definitions. A graphic is something that relates x- and y- coordinates to colors. You give it an x-y pair; it gives you a color.
91+
Let's get a bit more mathematical (or denotational)[1](#1) with our definitions. A graphic is something that relates x- and y- coordinates to colors. You give it an x-y pair; it gives you a color.
6592

6693
Here's the difference between bitmaps and SVGs: what kind of numbers make up the x-y pairs?
6794

@@ -114,7 +141,7 @@ In most programming, time is discrete. The ticks of time can be counted one-by-o
114141

115142
Now let's return to the original question that inspired FRP:
116143

117-
> What would programming look like if time were continuous?
144+
> What would it be like to program in continuous time?
118145
119146
#### What is an animation?
120147

@@ -190,7 +217,7 @@ const example6 = layer([
190217
191218
## Interactivity
192219
193-
The above animations are neat, but they are static in the sense that movies are static: no interactivity. We want to be able to press, click, type, and play with our screens. Let's go deeper into the DCTP rabbithole.
220+
The above animations are neat, but there's no interactivity. We want to be able to press, click, type, and play with our screens. Let's go deeper into the DCTP rabbithole.
194221
195222
### Behaviors and Events
196223
@@ -209,7 +236,7 @@ Behaviors are continuous functions of time:
209236
210237
![](https://camo.githubusercontent.com/bdbe25d1c8cf3490714fcf8d90039be58afcda35/68747470733a2f2f7261776769742e636f6d2f66756e6b69612f686172656163746976652f6d61737465722f666967757265732f73747265616d2e737667)
211238
212-
_Graphic of EVents from the [Hareactive documentation](https://github.com/funkia/hareactive)_
239+
_Graphic of Events from the [Hareactive documentation](https://github.com/funkia/hareactive)_
213240
214241
Events are discrete occurrences in time:
215242
@@ -223,21 +250,63 @@ The above animation code was purposefully simplisitic: we literally used pure, m
223250
224251
Let's start with a simple counter button:
225252
253+
<button onclick="ex1.innerText -= -1">Count!</button><span id="ex1" >0</span>
254+
255+
```javascript
256+
const counter = function*() {
257+
// put a button on the screen
258+
// `clickEvent` is the stream of all click events on that button
259+
const {click: clickEvent} = yield button("Count!")
260+
261+
// calculate the number of clicks on the button
262+
// `scan` is like fold or reduce, but over streams
263+
// `liftNow` and `sample` are outside the scope of this essay
264+
const clicks = yield liftNow(sample(scan((n, m) => m + 1, 0, clickEvent)));
265+
266+
// put the clicks count on the screen
267+
yield span(clicks)
268+
};
269+
```
270+
[![Edit Turbine Counter](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/rym2pwy3lp?module=%2Fsrc%2Findex.js)
271+
272+
[TODO drawn flows?]
226273
227274
### Cyclical Flows
228275
229276
What if we want the button to count inside itself?
230277
278+
<button onclick="this.innerText -= -1">0</button>
279+
280+
```javascript
281+
const counter = loop(
282+
// create a cycle with `loop`
283+
// the `clicks` Behavior (defined in the function below) is passed in
284+
({ clicks }) => function*() {
285+
286+
// use the `clicks` Behavior BEFORE IT's DEFINED
287+
const { click: clickEvent } = yield button(clicks);
288+
289+
// define `clicks_`
290+
const clicks_ = yield liftNow(sample(scan((n, m) => m + 1, 0, clickEvent)));
291+
292+
// set `clicks` to `clicks_` to tie the recursive knot
293+
return { clicks: clicks_ };
294+
}
295+
);
296+
```
297+
[![Edit buttons that create buttons](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/xorqy1q73q)
298+
299+
[TODO drawn flows?]
300+
231301
### Higher-order Flows
232302
233-
What if we want a variable number of counters? [maybe simpler]
303+
TODO
234304
235305
### Higher-order & Cyclical Flows
236306
237-
What if we want counters that make counters that make counters...? [maybe simplier]
238-
307+
What if we want a button that makes buttons that make buttons... but only the odd buttons can make buttons? This example may seem contrived, but it's a good minimal example to test the expressivity of a UI paradigm.
239308
240-
This example may seem contrived, but it's a good minimal example to test the expressivity of a UI paradigm.
309+
https://codesandbox.io/s/xorqy1q73q
241310
242311
### Visualizing Flows
243312
@@ -249,26 +318,9 @@ I have a hunch: visualize the flows.
249318
250319
There's been some interesting work done here [TODO linkify], and I'm hoping to further it by building similar visualization tools for Hareactive and Turbine.
251320
252-
## "Why program with continuous time?"
253-
254-
[TODO this section needs cleaning]
255-
256-
Of course, for the computer to render the above graphics on the screen, it must at some point convert the continuous time and space to discretized pixels and ticks of time. So what's the point of programming in continuous time if it will eventually be discretized?
257-
258-
There are a [lot](https://github.com/conal/talk-2014-bayhac-denotational-design#why-continuous-time-matters) of [reasons](http://conal.net/blog/posts/why-program-with-continuous-time). The most compelling argument for me is for the same reason we use SVGs: resolution independence. We want to be able to transform our programs "in time and space with ease and without propagating and amplifying sampling artifacts." We want to discretize at the last possible moment, and stay as abstract as possible for as long as possible.
259-
260-
Aren't spreadsheets wonderful? A key to their success is that there is no control flow, no sequencing of instructions. Only data flow.
261-
262-
In [The Next 700 Programming Languages](https://www.cs.cmu.edu/~crary/819-f09/Landin66.pdf), Peter Landin calls such languages "denotative" when they contain only nested mathmatical expressions, and each expression *denotes* (can be model by) some mathmatical object. And, "The antithesis of denotative is 'imperative.'"
263-
264-
As Conal says:
265-
266-
> There is a lot of confusion about the meaning of “functional” and “declarative” as descriptions of programming languages and paradigms.... I’ve started using the more specific term “denotational programming” in my blog subtitle and elsewhere, as an alternative to what I used to call “functional programming”. While there are other notions of “functional”, applicable even to monadic IO, I think “denotational” captures the fundamental and far-reaching benefits that we called “good for reasoning about” and “powerfully compositional”. - [Is Haskell a purely functional language?](http://conal.net/blog/posts/is-haskell-a-purely-functional-language)
267-
268-
Haskell is such a denotative lanugage... That is, except for monads.
269-
270-
[TODO Explain why continuous time (and laziness) are key for compositionality and modularity, maybe citing my FRP paper]
321+
## Denotational Programming Beyond User Interfaces
271322
323+
TODO
272324
273325
### Monads are Imperitive
274326
@@ -308,13 +360,23 @@ One day in the shower, I was wondering how to incorporate HTTP requests into the
308360
309361
The same is true of all imperative APIs, including databases, files, sockets, etc. It's not that we have to abandon these technologies entirely. But only as the _implementation_ of a denotative programming system. The computer's job should making HTTP requets, reading and writing to files and databases, on your behalf, just like React mutates the DOM on your behalf.
310362
311-
## Common Gotchas
363+
## FAQ and Common Gotchas
364+
365+
### Why program with continuous time?
366+
367+
Of course, for the computer to render animations on the screen, it must at some point convert the continuous time and space to discretized pixels and ticks of time. So what's the point of programming in continuous time if it will eventually be discretized?
368+
369+
There are a [lot](https://github.com/conal/talk-2014-bayhac-denotational-design#why-continuous-time-matters) of [reasons](http://conal.net/blog/posts/why-program-with-continuous-time). The most compelling argument for me is for the same reason we use SVGs: resolution independence. We want to be able to transform our programs "in time and space with ease and without propagating and amplifying sampling artifacts." We want to discretize at the last possible moment, and stay as abstract as possible for as long as possible.
370+
371+
### Thinking about DAGs or propagation
312372
313-
DCTP is notoriously difficult to understand. Even if you get most of it, you are likely not yet entirely rid of imperitive thinking habits.
373+
A very common misconception with DCTP is confusing it with its implementation details. If you catch yourself thinking of DCTP as a DAG (directed acyclic graph), you still haven't quite gotten it.
314374
315-
### Thinking about DAGs
375+
> Every time you hear somebody talk about FRP in terms of graphs or propagation or something like that, they are missing the point entirely. Because they are taking about some sort of operational, mechanistic model, not about what it means.
376+
>
377+
> - Conal Elliott on the Haskellcast Podcast
316378
317-
A very common misconception with DCTP is confusing it with its implementation details. If you catch yourself thinking of DCTP as a DAG (directed acyclic graph), you still haven't quite gotten it. The builder of a DCTP framework or library _may_ decided to choose a DAG as an internal data structure, but they may choose an entirely different underlying evaluation strategy. In fact, a DAG is likely the wrong structure for DCTP because DAGs are (definitionally) acyclic, but DCTP often requires cycles (recursively defined Behaviors and Events) to represent the full range of user interfaces.
379+
The builder of a DCTP framework or library _may_ decided to choose a DAG as an internal data structure, but they may choose an entirely different underlying evaluation strategy. In fact, a DAG is likely the wrong structure for DCTP because DAGs are (definitionally) acyclic, but DCTP often requires cycles (recursively defined Behaviors and Events) to represent the full range of user interfaces.
318380
319381
### Doing vs Being
320382
@@ -324,12 +386,6 @@ If you find describing your code in terms of _steps_, you've probably slipped ba
324386
325387
I find it helpful to ask myself: What _is_ it? [TODO]
326388
327-
In [What's Functional Programming All About?](http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbout.html), Li Hayoi explains: "The core of Functional Programming [or denotative programming] is thinking about data-flow rather than control-flow." He demostrates this beautifully by converting an imperitive tiramisu recipe to a dataflow diagram:
328-
329-
![](https://user-images.githubusercontent.com/2288939/51426743-e7fc2400-1be6-11e9-9aa6-1c45d3c8f83e.png)
330-
331-
[TODO]
332-
333389
### Performance
334390
335391
It's well known that FRP has suffered space and time leaks. People often complain about the performance of denotational langauges like Haskell.
@@ -346,6 +402,7 @@ When your code is abstract and free of imperitive, technological, operational co
346402
* [Let's reinvent FRP](http://vindum.io/blog/lets-reinvent-frp/) by Simon Friis Vindum
347403
* [The Essense and Origins of FRP](https://github.com/conal/talk-2015-essence-and-origins-of-frp)
348404
* [Functional Reactive Animation](http://conal.net/papers/icfp97/) - the original FRP paper by Conal Elliott and Paul Hudak
405+
* [The introduction to Reactive Programming you've been missing](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754) by Andre Staltz
349406
350407
## Notes
351408
@@ -357,4 +414,4 @@ https://stackoverflow.com/questions/1028250/what-is-functional-reactive-programm
357414
358415
https://futureofcoding.org/notes/conal-elliott/
359416
360-
<a name="1" href="#1">[1]</a> - The "D" in DCTP stands for "denotational semantics." The original name for denotational semantics was "mathematical semantics". It was pioneered by Chris Strachey and Dana Scott in the early 1970s. It is an approach to model a programming language with mathematical objects. For example, in this essay we model static graphics as a functions from `x` and `y` to `Color` and moving animations from `x`, `y`, and `t` to `Color`. You can learn more about denotational design and semantics from Conal's [video](https://www.youtube.com/watch?v=bmKYiUOEo2A) and [paper](http://conal.net/papers/type-class-morphisms/).
417+
<a name="1" href="#1">[1]</a> - The "D" in DCTP stands for "denotational semantics." The original name for denotational semantics was "mathematical semantics". It was pioneered by Chris Strachey and Dana Scott in the early 1970s. It is an approach to model a programming language with mathematical objects. For example, in this essay we model static graphics as a functions from `x` and `y` to `Color` and moving animations from `x`, `y`, and `t` to `Color`. You can learn more about denotational design and semantics from Conal's [video](https://www.youtube.com/watch?v=bmKYiUOEo2A) and [paper](http://conal.net/papers/type-class-morphisms/).

0 commit comments

Comments
 (0)