Fork me on GitHub
#missionary
<
2023-08-21
>
Ben Sless12:08:43

Since cloroutine (no channel for it and it's what missionary is built on, so :man-shrugging: ) makes it trivial to implement shift and reset, have you given some thought to implementing algebraic effects with it?

☺️ 2
clojure-spin 2
Dustin Getz12:08:05

Speaking for myself not Leo, Geoffrey and I have considered algebraic effects several times for the use case of electric-UI but each time, so far, ended up finding a better way

Dustin Getz12:08:20

Do you have a use case in mind?

Ben Sless13:08:28

Backend programming in particular. Lots of effects going around, mount is terrible, component puts people off, integrant is all over the place Maybe just not have any DI framework for writing code, just write code?

Dustin Getz13:08:01

Have you considered the already existing correspondence between Electric and DI frameworks? I.e. both have a reactive component lifecycle

Ben Sless13:08:02

That might be more than I need. I wouldn't know exactly where to start with electric building an api server, but I would with algebraic effects

Dustin Getz13:08:22

Comparison of Component and Electric for DI

Dustin Getz13:08:07

Just a sketch I haven't thought very hard about this, the "real" DI systems surely have polish for that use case that we don't have

Dustin Getz13:08:14

i.e. hot code reloading situations or something idk

Dustin Getz13:08:25

I haven't really used them

Dustin Getz13:08:54

Likely the system components (i.e. database) would be Electric bindings i.e. reactive dynamic scope

Ben Sless13:08:07

Having to pass the arguments explicitly sort if defies the point if the exercise Yeah, there's an option to make the components dynamic, but that also raises the question how that will differ from regular old clojure

Ben Sless13:08:09

With algebraic effects they'll still be dynamically bound, but you go to function handlers (transfer of control) instead of access stateful objects bound dynamically

👍 2
Ben Sless13:08:44

Is it better to bind the handlers? Is there any value to using algebraic effects over just dynamically binding functions?

Dustin Getz13:08:33

Electric dynamic scope differs from Clojure dynamic scope in that the bindings are stateful and have component lifecycle, i.e. Electric instances are objects. Clojure bindings are just values

Dustin Getz13:08:35

yeah idk what the added value of algebraic effects is for this use case

Dustin Getz13:08:59

here is the relevant tutorial about Electric lifecycle which is relevant to this discussion - not sure if you have seen it

Dustin Getz13:08:38

the latest missionary changes (to m/signal) i think are related to this discussion too, you don't need Electric for this, i think Electric is just the syntax sugar that makes it palatable for this use case

Ben Sless13:08:56

Have, but haven't dug too deeply into it. I think I should try to sketch out example code and see how an implementation would look like

Dustin Getz13:08:26

Sure, if you gave us a sketch and list of operational aspects/requirements to consider that would be interesting for us to think about and valuable

Dustin Getz13:08:53

not sure I'm fully in sync w/ you but whatever

Dustin Getz13:08:14

What in your opinion is the current best DI framework for Clojure?

Ben Sless13:08:25

Component, due to law of preservation of suck

Dustin Getz13:08:48

lol, what's that

Ben Sless13:08:31

There are preservation laws in the universe. Momentum, angular momentum, energy, turns out that things sucking is another thing which is preserved. So if DI sucks, all DI frameworks will suck in the same amount, just maybe in a different way

❤️ 2
Ben Sless13:08:03

So instead, I wrote a helper for Component to help it look slightly less annoying to me https://github.com/bsless/companion/blob/master/src/bsless/companion.clj

👀 2
Ben Sless13:08:33

The suck was transferred to other developers who have to think about another layer of abstraction and in how it slightly restricts access patterns to components

👍 2
Dustin Getz13:08:06

our theory/worldview with Electric is that "having actual lambda" is the answer to that – if you are making something that is supposed to compose, you either have lambda or you don't, where "don't" is the root cause of "preservation of suck"

Dustin Getz13:08:12

conjecture: all programming infrastructure will eventually take the form of programming language infrastructure

Ben Sless13:08:35

Erlang is standing over the horizon laughing at us

👀 2
Dustin Getz13:08:58

evidence: Temporal (durable execution), JVM garbage collection, React (reactive execution embedded in JS and the ways in which it sucks are the places where it fails to have fully reactive control flow), Electric network transparency, async/await, generators

Ben Sless13:08:17

In Erlang ALL infrastructure is programming language infrastructure, your code runs just as well on a cluster of 1000 nodes and on your local machine

Ben Sless13:08:30

It also has GC, is reactive, allows for atomic deployments of code

Ben Sless13:08:38

another aspect it sublimated is error handling itself

Ben Sless13:08:12

And for fun, behaviors are like the "right way" of doing interfaces

👀 2
Dustin Getz13:08:51

functional composition model / functional concurrency primitives like missionary?

Ben Sless14:08:52

No, generic machines specified by callbacks for reacting for events and potentially advancing internal state

Ben Sless14:08:21

The idea is that any system can be built by assembling such machines, and that the set of behaviors you actually want for machines in a system is pretty limited

nivekuil14:08:31

would be curious to know what you think about https://github.com/nivekuil/nexus, which is my (imo successful) attempt at replacing integrant with a generic logic engine. I think backward chaining inference is a better fit than (push?) FRP that electric implements, for DI. I'd also be curious to read a comparison between FRP and inference engines in general

👀 2
nivekuil14:08:02

my guess is they come from different schools of thought but there's significant practical overlap

Dustin Getz14:08:04

electric is push/pull, i.e. "lazy sampling"

Ben Sless14:08:21

I have to say I personally like Nexus, although I consider it using a nuke to kill a mouse.

Ben Sless14:08:44

I wonder if algebraic effects (e.g. handlers) are neither push nor pull, they're just immanent

nivekuil14:08:02

yeah, it's a nuke. Agreed

Dustin Getz14:08:09

algebraic effects are orthogonal

nivekuil14:08:58

main benefit is the ergonomics in use of the auto caching, which as Dustin mentioned is one of those specific touches orthogonal to the paradigm

Dustin Getz14:08:07

> Components specify the data they need and are used like a function with their arguments automatically passed to them, Fulcro-style. this smells like the "almost a function but not quite" problem, I propose that all differences between this and actual functions are bugs

nivekuil14:08:21

But I think it's a nuke worth adopting more broadly. I'm using a similar approach to do distributed configuration like https://web.archive.org/web/20030218034509/http://www.research.microsoft.com/research/dtg/davidhov/pap.htm

nivekuil14:08:53

I'm increasingly coming to believe that configuration encompasses most of why computers suck

nivekuil14:08:12

and DI is a subset of configuration

Dustin Getz14:08:29

"DI as configuration" worldview excludes control flow, now your XML config language has <if> and <for> directives in it

nivekuil14:08:14

Not sure what you mean by control flow, the point is to have the computer figure it out. Dustin have you seen this critique of pure function composition https://youtu.be/XONRaJJAhpA?t=15m27s

Dustin Getz14:08:22

have not seen

Dustin Getz14:08:06

he seems to be criticizing imperative programming (which Clojure is)

Dustin Getz14:08:18

i'll accept (or conjecture) that "declarative programming" and "configuration" are the same thing

Dustin Getz14:08:32

declarative programming means programming without control flow

Dustin Getz14:08:50

that means you need to abstract over cardinality, for starters, because declarative programming has no userland loops

Dustin Getz14:08:50

control flow = if, for, recur, lambda, throw/try/catch, etc

Dustin Getz14:08:03

example: HTML does not have control flow

Dustin Getz14:08:24

example: XML does not have control flow, until it does

Dustin Getz14:08:57

example: GraphQL does not have control flow, until it does - see @if

Dustin Getz14:08:55

Ironic coming from Facebook given the whole point of React is to embed view authoring DSL in javascript control flow, to stop writing {{if x: ...}} in our "declarative" view templates

nivekuil14:08:35

Configuration is the problem. I want X to work. To get X to work X needs to know Y. I don't want to think about Y, I only care about X, so I tell X everything I know and hope for the best. Declarative programming helps actualize that hope

Dustin Getz14:08:10

hope is only to the extent that you don't violate Greenspun's 10th, which every system eventually does

Dustin Getz14:08:21

hence Ben's principle of suck preservation

Dustin Getz14:08:59

I don't reject your argument entirely; HFQL is declarative (though it is embedded in Electric's composition model, which is the critical point)

Dustin Getz14:08:09

Electric itself is declarative with respect to network and declarative with respect to reactive evaluation, however this requires a nuanced worldview based on homoiconicity where the lisp program reifies all the control flow statements statically into the AST, which the Electric compiler then uses to "have the computer figure it out"

Dustin Getz14:08:39

which is kinda the end of the configuration-driven worldview, Lisp is that, the program is data i.e. configured

Dustin Getz14:08:17

hence the emergence of Greenspun's 10th Rule – applied here, it means that any configuration language will eventually need control flow, which means your configuration language must be exactly Lisp

nivekuil14:08:44

It has to be imperative at some level but turing incompleteness is the goal. I want to be just able to give the CenturyLink guy my account number and have my internet fixed so I can stop typing on my phone. But of course someone has to know how to fix it

nivekuil14:08:36

And of course the more proximal the condition is to the problem the more you can charge for that condition as a solution. Framers get paid a lot worse than finish carpenters

Dustin Getz14:08:40

"imperative" I didn't say that

Ben Sless14:08:48

Configuration is just a private case of dependency, which is a private case of ordering, which is why logic programming and rule engines are fun

👍 2
Ben Sless14:08:21

I don't want to have to figure out in which order anything needs to happen

👍 2
Ben Sless14:08:27

which Pathom sort of does well

Dustin Getz14:08:00

functional programming gives you declarative wrt evaluation order

Dustin Getz14:08:18

basically DAGs

Ben Sless14:08:49

let x = y in body is not declarative, you have to have x bound before you can use it in body

Dustin Getz14:08:14

not so in Haskell

Ben Sless14:08:19

so unless let bindings (and function calls) are not functional, I don't see it

Dustin Getz14:08:24

recursive let

Dustin Getz14:08:00

here's Clojure psuedocode

(defn Fix1 [f]
  (let [x (f x)]
    x))

Dustin Getz14:08:46

The need for recursive let comes up a lot in UI programming

Dustin Getz14:08:25

This doesn't work yet in Electric but we'd like it to weight depends on bmi, bmi depends on weight

(e/defn bmi-component []
    (let [height (Slider. 170 100 220)]
        ; Looped interdependent bindings
      (let [weight (Slider. (* (or bmi 50) height height) 30 150)
            bmi (Slider. (/ (or weight 70) (* height height)) 10 50)]
        (dom/p (dom/text "BMI: ")
          (dom/text bmi)))))

Dustin Getz14:08:44

The workaround (that Reagent tutorial uses) is to introduce an atom to "tie the knot"

Ben Sless15:08:16

Recursive bindings just take you from dag to dg

Ben Sless15:08:03

Which is okay when you do graph reduction

Ben Sless15:08:31

But it's only limited to occur in the same expression

Dustin Getz15:08:29

ok, i guess i dont understand your objection to "FP gives declarative wrt evaluation order"

Dustin Getz15:08:27

oh you're saying datalog lets you compile declarative query into a query plan, user did not specify the plan

Ben Sless15:08:05

Exactly. Same for prolog and generally logic languages. Imagine execution plan in general being incidental

Ben Sless15:08:23

Which pathom sort of does

Dustin Getz15:08:20

I accept that, with the caveat that we have application glue code (control flow) between our queries

Dustin Getz15:08:06

better to have a trap door down to control flow layer from inside the queries without leaving the DSL's composition model entirely

Dustin Getz15:08:14

so you end up with a Rama layer

Dustin Getz15:08:45

conjecture: programming languages and databases are the same thing

Dustin Getz15:08:58

pretty sure you accept that

Ben Sless15:08:16

sort of counter argument - no, but they should be

Dustin Getz15:08:30

so we're right back to Greenspun's 10th and Lisp

Dustin Getz15:08:35

because applications are queries; i.e. application views are projections over the event log

Dustin Getz15:08:05

the control flow in a user interface is part of the query

Dustin Getz15:08:43

classical SQL/datalog query langs are too declarative and its the source of a massive seam through the entire application

Ben Sless15:08:26

Event sourcing in general. of which CQRS is a particular case

Ben Sless15:08:16

Maybe they're too declarative because we're still missing something. Until then we need escape hatches

Dustin Getz16:08:12

i mean we know what they're msising, analyse it from the perspective of composition as it exists in lisp

Dustin Getz16:08:48

we want to weave in lambdas (with control flow) at arbitrary points in the query, e.g. a stored procedure on the inside

Dustin Getz16:08:11

we want the query when it finishes to return control to lisp, i.e. a stored procedure on the outside

Dustin Getz16:08:44

we want to factor apart our queries into reusable units and compose them together, including higher order combinators – that's lambda

Dustin Getz16:08:35

we want the end-to-end composition model to be seamless and have the same semantics everywhere

Dustin Getz16:08:45

(reactive, network-transparent, durable, etc)

Dustin Getz16:08:48

in the middle of a query, we want to call out to another system, and then return control back to the query, and we want uniform semantics all the way through this

nivekuil16:08:55

I don&#x27;t understand how something can be too declarative. If your app isn&#x27;t just a view then it&#x27;s not sufficient, but to the extent that you need a view the fully declarative layer, read-optimized layer is really nice to have.

Dustin Getz16:08:56

an example is React is the wrong amount declarative (it does not understand your js control flow) which causes the evaluation model to suffer performance problems, over-render etc

Dustin Getz16:08:37

the theory was that views should be declarative and don't need control flow, react has conclusively demonstrated that to be wrong

Dustin Getz16:08:20

the strongest statement that can be made is that you can interweave declarative abstractions into your app at various points, at the tradeoff of expressive power

nivekuil16:08:18

isn&#x27;t the escape valve for that react behavior like zustand, re-frame subscriptions etc.

nivekuil16:08:32

I understand that the problem with fine grained reactivity everywhere is it sucks to debug, so fulcro puts everything into a big map (and then just renders from root, leading to the performance issues you describe.) Fulcro also tried keeping runtime indexes for more fine grained rendering but that turned out to be even slower. So I wonder how hard it would be to get electric's compile-time dependency tracking as a hook

nivekuil16:08:31

also I just realized I need to fix my matrix bot... how is ' being hex encoded

Eric Dvorsak11:04:37

> I think I should try to sketch out example code and see how an implementation would look like @UK0810AQ2 have you explored this more since? I am also curious on how missionary could help make a better solution mount/component

Ben Sless11:04:10

It's been a busy year, haven't had time for half the things I would have wanted