Fork me on GitHub
#hyperfiddle
<
2022-05-02
>
Daniel Basner13:05:36

is the demo you linked to on twitter at the end of the hytradboi talk (great job btw!) different from previous demos? I have twitter blocked on my devices so I cannot check haha

Dustin Getz13:05:03

The CRUD-app-as-an-expression hypermedia demo did not make it out on time; soon! I haven't had time to narrate and produce a good video

Dustin Getz13:05:19

probably next week

Daniel Basner13:05:11

ok, take your time! If you could post it here in addition to twitter I’d be very appreciative

Dustin Getz14:05:26

Sure, will do

Dustin Getz14:05:40

For those out of the loop, we launched a Photon 10min lightning talk on Friday which became public on Saturday. Video link and hype: https://twitter.com/dustingetz/status/1520397540386091009 https://news.ycombinator.com/item?id=31217448 Best place for Q&A is r/clojure: https://www.reddit.com/r/Clojure/comments/ufbzp6/uis_are_streaming_dags_hyperfiddlephoton_a/

🙌 2
🎉 3
nottmey14:05:06

Hi Dustin, I really like the Idea and would love to see this architecture compete against nuxt.js, next.js, etc. frameworks. How can outside people help you progress with that? 🙂 (Besides boosting the tweet 😄)

❤️ 1
Dustin Getz14:05:10

If you have some free time, you can try it out with me on zoom (I will help you clone the repo and manually onboard you), interested? First three people are trying it in the next week or so

Ben Sless17:05:05

Since this is equivalent in some sense to inlining, how do you solve the problem of closures duplicating work?

Dustin Getz18:05:00

Closures are higher order DAGs (DAG as a Value); this has monadic structure and therefore the DAG is dynamic, imagine a DAG evolving/animating over time as you navigate through screens of a UI the DAG updates to reflect the new set of edges that are active. This structure is called "self adjusting computation" per https://blog.janestreet.com/breaking-down-frp/

Dustin Getz18:05:07

The article is very old (2014), this statement from the article is flat out wrong: "As you might expect, the lack of history-sensitivity makes SAC less suitable for writing user interfaces"

Ben Sless18:05:52

welp, time to do some reading

Ben Sless18:05:45

I know HVM managed to solve graph reduction from one direction by implementing copying correctly, now I got to understand what you did

Dustin Getz18:05:54

A simpler hello world case to reason about first is an if statement, the compiler knows statically that there are two branches and only one can be active at a time and the DAG can switch between them. Even this simple DAG has a degree of dynamism, imagine the DAG animating as it flips between the two states

Ben Sless18:05:42

when about a case like: (fn [x] (let [x (+ n 2)] (fn [y] (+ y x))) This function returns a graph, will x's expression be inlined in it?

Ben Sless18:05:33

I see how an if doesn't duplicate work in call-by-need, but not sure regarding the example

Dustin Getz18:05:38

“DAG” “AST” “lisp form as data structure” are all essentially synonyms, all are abstract until an evaluator is provided. So it is 100% okay to reason about this example as regular lisp closures; the binding named by x is what is closed over. it turns out that if you provide a reactive eval you will get a reactive closure that does “the right thing”. The term “DAG” here can just be thrown away, it's just a helpful metaphor

Dustin Getz18:05:41

if you want to reason about it as a DAG: let creates a named edge, closures are DAG values, and you'd need to recognize DAG-of-DAG structure as symmetrical to promise-of-promise; the evaluator flattens it at runtime

Dustin Getz18:05:14

same structure as fn of fn; you need to actually evaluate and run the fns to flatten the structure and see which way the fns went per whatever runtime control flow logic around them

Ben Sless19:05:31

my question essentially is what are the call semantics, call by value or call by need

Ben Sless19:05:38

Let's take this example:

(defn foo [n] (let [x (+ n 2)] (fn [y] (+ y x))))

(defn bar
  []
  (let [f (foo 5)]
    (map foo [1 2 3])))

Ben Sless19:05:23

If we do evaluation by substitution then we might end up calculating (+ n 2) 3 times

Ben Sless19:05:14

If evaluate by value then it's evaluated once

Dustin Getz23:05:32

> Since this is equivalent in some sense to inlining > A good compiler must inline many of these calls to recover an eciently executable program I dont think what we're doing is inlining

Dustin Getz23:05:30

This passes, (+ n 2) is computed once

Dustin Getz23:05:12

p/fn are capitalized and called with (new) aka . for great reasons: 1. for full clojure compat we need to support regular both normal Clojure function calls (trace!, range, m/watch, rcf/!) and reactive function calls (Bar, Foo, F) 2. without a type inferencer, you need syntax to disambiguate the two types of calls (same as hiccup). The compiler could infer top level static calls with metadata on var, but the compiler cannot infer dynamic calls, so you need syntax 3. It turns out that reactive functions can be seen as actors, Photon functions are objects, they have a history of states over time, they have a component lifecycle like React, you send events/messages to them -> they maintain their state -> emit new events/messages. So they are called/booted/constructed with (new) 4. foreign missionary flows are also joined with (new) - as in (new (m/watch ...)), it's not a coincidence

Dustin Getz00:05:35

Here is the compiler artifacts, (steady x) is (m/watch (atom x)); (latest-apply f a b) is (m/latest f a b) with some error handling. This is as deep as I go, beyond this point is "Leo stuff"

Dustin Getz00:05:38

the key point is that p/fn ends up becoming a real clojure fn; let is real clojure let, it's the bindings that are all lifted into missionary signals, so the compiler basically calls Photon functions via m/latest

Ben Sless12:05:26

That's a lot to take in

Dustin Getz13:05:29

Thank you for saying that so I have the feedback - this is my first time trying to explain it

Dustin Getz13:05:42

The answer to your question is it's "call by value"

Dameon15:05:12

I’m interested in trying to work with this. The model seems super compelling.

🙂 1
Daniel Jomphe21:05:37

For hyperfiddle's rcf/tests macro, let me suggest you normalize and suggest every user to require it aliased instead of referred, so that everywhere on the web, where someone posts screenshots like the following one, people searching google might find your lib easily.

👍 2