<< The average person tends to have either less than eight tabs open, or to add tabs without organization until declaring “tab bankruptcy” and starting fresh. >>

yeah, I'm the... second one

(checks browser; it reports 'new mathematical research needed in order to determine if your number of open tabs is even theoretically countably infinite')

freecodecamp.org/news/lossless

@natecull i obstinately refuse to ever close tabs even while my computer struggles and furiously diskswaps.
freeing up space memory and cpu time sounds like the garbage collector’s job. why is my computer making me do its job?

@zensaiyuki exactly how I feel, yeah.

I end up restarting Firefox instead of closing tabs

because I *might* need one one day

@zensaiyuki Actually, it's far worse than that.

The act of clicking on a tab to close it means i'm likely to read the page again, and then I'm likely to click more links. Into new tabs, of course.

@natecull i sorta want a browser with a different UI paradigm where pages exist in a kind of zoomable space, history stacks are visualised as skeuomorphic stacks of paper, and “new tab” just makes a new stack. a heuristic dumps old stacks to disk so they don’t consume memory or cpu, but if you go back they can rehydrate, and ideally not in a way that is effectively reloading the page, though that might be unavoidable.

@dredmorbius @natecull that surely is interesting but i don’t see the connection

@zensaiyuki @dredmorbius

It's kind of relevant, at least to my interests.

My 'webscape' is my set of open tabs, but only because that's all today's browsers give me. What I *really* want is yeah, massive and pervasive caching. Everything I've ever browsed, I want it downloaded and not to hit the Internet again unless it absolutely needs to. And then I want to search that stuff locally.

Today's browsers assume 'stuff lives primarily in the cloud/web,' but I want the reverse of that.

@natecull @dredmorbius ah yes that’s exactly what i want. that’s what i’m trying to build now actually. you’ll have to be patient though i have been trying to build it for 10 years, I’m just so bad at it.

@zensaiyuki @dredmorbius

Hmm. I wonder if just automatic saving of all web pages to a file/folder, plus a file containing a history of URLs.... wouldn't go a very long way towards this.

perhaps even just a local web proxy service, implemented in Node.js

The point is its database should be engineered for maximum accessibility of data by other applications. So a filesystem, for preference, not a database.

@zensaiyuki @dredmorbius

( I suppose a database for *indexes*, for speed, but the database must always be able to be regenerated from the filesystem )

@zensaiyuki @dredmorbius

Okay so.... does this already exist? Must be a million Node.js personal web proxies by now..... ?

@natecull @dredmorbius i’ve come to the conclusion that the only way to implement what I want, needs access to all the tab’s running state and its history stack. the only ways to get that are in an extension or a fully custom browser, like an electron app.

@natecull @dredmorbius and yes there are a gajillion proxy things. and I have been evaluating them for something I can build off.

@natecull @dredmorbius a lot of the reason it’s taking me so long is i keep thinking of things i want it to do, to the point it becomes unclear what the thing actually is.

@natecull @dredmorbius and then when i decide i need to write a programming language to write it in first it’s all over. i call it “the aristocrats”. actually the design document has the title “the big scope creep”

Follow

@natecull @dredmorbius is it a floor wax? is it a healthy toast spread? is it a face moisturiser? i dunno. it came to me in a dream 15 years ago and morpheus picked the wrong guy.

@zensaiyuki @dredmorbius

ooh, literal dream projects! I like those.

I had something similar happen to me around 2006. Still don't quite grasp what my dream-self was trying to express.

(although a large part of it seems to have been 'functional reactive' before that became popular with React.js and Elm... sadly, I didn't have any way of expressing what I want, and I still don't quite grasp what the core elements of FRP are)

@zensaiyuki @dredmorbius

My gut feeling though was and still is that we ought to be able to make both GUI and network programming much, much simpler than they are by expressing them as declaratively as possible and letting a simple runtime engine stitch together dataflow paths.

How exactly that runtime engine works, though, my dream-self left as an exercise for the reader and so I still don't have a handle on it.

Something like 'pure-functional reactive RDF' was my feeling, but... how?

@zensaiyuki @dredmorbius

I like what Elm is *trying* to do, but, I don't think it's got there.

Elm is all based on the ML family of programming languages and those just rub me up the wrong way, because their fundamental structures don't seem recursively decomposable at runtime. Too much done by the compiler.

We need a core algorithm way simpler; about two orders of magnitude simpler.

Elm's 'records' need to be expressible at runtime; and all of the source code must be expressible in them.

@zensaiyuki @dredmorbius

(This is why I went hunting for a syntax that would let me express 'record/object' like constructs as lists, in a logically/algebraically complete manner, and got kinda lost in the implications since they don't seem to QUITE map to existing structures. A key/value store or function doesn't seem to QUITE have enough degrees of freedom to express all permutations of 'a set of Lisp Cons cells', and that worries me. And I can find no literature on anyone else doing that.)

@natecull @dredmorbius the other thing about quartz composer is its file format is a plist, (apple’s version of json from before json existed) which you can open with apple’s plist editor. it gives you a massive clue as to how it’s implemented.

@zensaiyuki @dredmorbius

Interesting! What does Quartz Composer do that React did badly or left out? I have no experience with react.

The thing that bugged me about Elm was just what kind of primitive 'FoldT' was... how we should track the accumulation of state over time in a FRP kernel, what primitives it should decompose into.

@natecull @dredmorbius the thing is that in quartz composer one of its patches is “javascript”, another one is “glsl” and it gives you a free form text editor with a really specific api. the implication is you can do FRP with scraps and bits and peices of well contained sandboxed imperative languages.
the whole model is that it’s like you’ve just got a pile of functions with multiparameters and multiple returns, and the plist is just a graph of how they’re hooked up.

@zensaiyuki @dredmorbius

That sounds... sensible?

Multiple returns as in coroutines and 'yield', or something else? What specifically about FRP requires them?

(I'm not surprised that it does, because I encountered something similar, but finding that plus the general lack of interest in reliable co-routine support in most languages shook my confidence.)

@zensaiyuki @dredmorbius

(The other confidence-shaking thing being that it seemed like the wiring-up graph between components would likely change over time, and I still don't understand how to handle that well, and simply. Eg if you disconnect from a stream because you've gone down the other path of an 'if' block, how do you reconnect?)

@natecull @dredmorbius frp doesn’t require them, exactly. it’s just a really convenient way to model the structure of a program. in a normal program you mightget some sturcture as a return value, and a bunch of code is effectively just “glue”, parsing oyt useful results and calling other functions. in quarts compuser you just hook a wire from an output value to an input value. the essence of frp is signals. a patch bay on a synth is like frp.

@zensaiyuki @dredmorbius

I guess what I'd like to see is the simplest possible reduction of FRP to its essentials, and expressible in short program text. I don't see why it needs to be graphical (could be expressed graphically, but would be simpler to reason about if it wasn't).

So I can see 'a patch is a function' easily enough. A function from an input value a time T to an output value at time T. The value might be a structure.

But, sometimes I think it would also need access to time T-1.

@zensaiyuki @dredmorbius

But I guess it would need access to 'an internal variable at time T-1', not an input. With a corresponding output to that variable at time T. Analogous to a cable pointing to itself.

@zensaiyuki @dredmorbius

So to me, one big question with FRP is 'how best to express self.state at time T-1?' I suppose maybe just as a magic variable...

But then, second question is, what happens to self.state if we disconnect and then reconnect from the input source? Is it always safe to just reset state to null?

@natecull @dredmorbius yes, i struggled with that too, but i found a solution. the sources are impure and not functional when you first run them. but as soon as you do, it becomes an immutable fact that those sources had value X at T time, and as long as you maintain that link between the value AND the time, there’s nothing impure about it. and you can even use it for time travelling debugging.

@zensaiyuki @dredmorbius

Right, that's similar to what I think. But then, all our signals kinda need to be a pair of value and time, and then we need to be EXTREMELY finnicky about time synchronisation. Which, over the Internet, could be a major nuisance. Or we have to use something other than a time - a sequence number, maybe. Then what happens if the sequence number resets after a lot of messages?

@zensaiyuki @dredmorbius

Anyway establishing all this sounds like the kind of fundamentals work that some computer science language design people should be working on, since it's literally their job, but each time I look over that fence, just.... crickets and tumbleweeds. And monads.

@natecull @dredmorbius yyep. so i’ve been spending a lot of years squeezing blood from that turnip and got a few drops. the main important thing in my view that i’ve gotten out of it is you want these algebraic relationships to hold:
r( events , t) = statet; ri(state) = dstatet; r(dstatet, t) = statet;

@natecull @dredmorbius i forgot to explain this.
here function “r” is a functional pure reducer (or foldr) function. it takes an array, a stream, or a real time feed of real world data, to produce a flattened “state” of the world. ri takes a state and attempts to produce a lossy value which can be fed into r to reproduce the original state. there’s 1000 details but this is the essence of state management in a pure frp world.

@zensaiyuki @dredmorbius

Interesting! Can you explain ri more? I assume r here is like Elm's FoldT?

@natecull @dredmorbius yeah, in react.js world this stuff is done by a library called redux. but redux is standalone so you can actually use it in your node projects without drinking allll the react.js koolaide.it’s basically just convenience functions for composing reducers to easily handle values that are deep heirarchical “json”.
(cont)

@natecull @dredmorbius ri here is just my own thoughtful conclusion that just converting from events to states and keeping all the events around for eternity isn’t going to cut it. you need an inverse function when you need to do things like schema changes, migrations, etc, and all you have is the current state. it produces a stream of events which, if fed into r, reproduces the original state. very akin to what sqldump does.

@natecull @dredmorbius what I am aiming for is figuring out a way that you can change r to something else, and it does something reasonable with the output of an older ri

@zensaiyuki @dredmorbius So ri = inverse of r; that seems logical and needed, yeah.

What I've been wrestling with is the idea that basically the state should BE the transaction so r would simply equal ri (or a minimal ri). Maybe that's a silly idea; it's certainly hard to square all the corners.

But eg the idea would be that each 'delta' would be an object... an object by itself would therefore contain both 'true' and 'false' as well as undefined field settings.

@zensaiyuki @dredmorbius One possible way of getting there is to make all objects end up in either True or False. This also allows us to store multiple atomic values per JSON property, since we put them in the key slot rather than the value slot.

So {a:1} becomes {a: {1: true}}

I think we could then express 'replace the entire record' as

{a: { {1: true}: true}

but sadly this isn't valid JSON, though it's valid Lua. So we need funky hacks running over JSON, which gets nasty.

Show more

@natecull @dredmorbius i’ve been down that road, and from a program point of view that’s what you want your functions to be spitting out as state updates. there are wrinkles though, to do with deltions and schema changes, that means you want the events in your event log to be essentially CRUD operations, probably automatically generated by a diff algorithm between the previous state and your new state.

Show more

@natecull @dredmorbius or maybe not. what I am really aiming for is a reasonable response to my frustrating experiences trying to actually use the output of an sqldump. maybe r just simply never changes and you do something else about the root issue.

@natecull @dredmorbius there’s a bunch of strategies for that. none of them are perfect, and which you cchoose depends on your system requirements. start at vector clocks and then surf to related algorithms until you find one you like.

@zensaiyuki @dredmorbius

Well ideally I'd like something that could run on a very small machine (32 bit or smaller) without big overhead, and could run a desktop, that might run for years without rebooting, and where some windows on the desktop might reflect Internet streams. It seems like that's in the ballpark of normal use these days.

@natecull @dredmorbius that’s not complicated, you just need your clock to always go forward, and not trust the timestamps of foreign sources completely. vector clocks are when you need to shuffle event logs together from multiple homogenous systems that aren’t perfectly synced, and where event order really matters.

@natecull @dredmorbius now what do you do with these immutable facts? you stick them into an event log, and build functions around querying the event log. there’s an entire prolog inspired language just for this one thing called datalog.

@zensaiyuki @dredmorbius

erm, Datalog. I am not really a fan of that? It seems like Prolog with literally all the good and important bits removed.

better than SQL, but that's a VERY low bar to clear.

@natecull @dredmorbius well, you don’t have to use it. but I found the event structure of datamic extemely helpful in smoking out practical problems they ran into building an event log.

here’s my note on that.
(i might have added vector clock)
event contains:
agent id
vector clock
wall clock
transaction id
entity id
attribute
value
added?

@zensaiyuki @dredmorbius

Oh the other thing I figured is it needs some way of expressing 'change over time to JSON-like field structure'.

Which I think means it either needs a 'not' operator, or a defined semantics for 'null/undefined'. Ideally, if your change is removing one key 10 levels deep from a million-key object, you don't have to repost all the other 999,999.

@zensaiyuki @dredmorbius

and that's where I wandered into the horrifying state of the semantics of 'not' in Prolog, and..... just ugh. I still have logic theory stuck to my boots.

@natecull @dredmorbius anyway, here’s the entirity of the vector clock algorithm because i found a really good summary:

@natecull @dredmorbius deletion isn’t real in frp. it’s just a different state for a key that you said existed and was an immutable and true fact. you wouldn’t lie to an event log would you?

@natecull @dredmorbius really for any system all you really need to achieve is for all the involved agents to agree on whether an event happened before or after another event. all the fancy clock algorithms really just amount to something extremely similar to your unihan sorting problem.

@natecull @dredmorbius exactly when, in absolute time something happened only matters when you add new agents, such as humans who want to compare the event to some other information source in meatspace. or some external api. and can get the broadstrokes easily enough, and focus your computational energy on disambiguating events that happen within a few seconds of each other.

@natecull @dredmorbius the main insight i got from the event structure in datomic here is it doesn’t try and capture a whole object in one event object. it does a keypath, a value, and a transaction id. you can do a whole object as s transaction with one event for each key, or a single key update. it doesn’t seem so important at first glance, but this elegantly solves a lot of tricky logic problems.

@natecull @dredmorbius and it reminds me a lot of how OSC works. i think a lot more stuff should adopt OSC.

@natecull @dredmorbius so the core constructs in fro are signals, which are generated by “sources”, (oscillators, time, random number) modified by “filters” (math operators) and then output to the user in “sinks”. (speakers, disolays) only filters are pure, sources are impure on input. sinks impure output.

@natecull @dredmorbius then, the interpreter simply runs the graph 60 times a second, passing parameters in, pulling return values out, parcelling them to new parameters. nothing is persisted between calls unless you go to a lot of effort. and it’s a live coding environment, the program runs while you edit it, so changes get instant feedback.

@natecull @dredmorbius if you want to get an intuitive feel for FRP you should try quartz composer, if you can. it’s a little bit hard to set up nowadays, but React.js is a badly fucked up copy of quartz composer concepts based on misunderstandings.

Sign in to participate in the conversation
Mastodon

Server run by the main developers of the project 🐘 It is not focused on any particular niche interest - everyone is welcome as long as you follow our code of conduct!