Closed askvortsov1 closed 3 months ago
Hey! Thanks a bunch for all the comments and proposals!
One of the larger changes I'm proposing in the accompanying PR is moving away from the "Graph" vs "Output Node" analogy for Computation vs Value in favor of a variety of others, such as:
- code logic vs memory block where output is written
- React component class vs component class instance
- source code vs assembly output
Honestly, I think the best analogy I've seen so far was the "Excel" analogy you used in one of the guide chapters. An Excel file typically has cells for all three of the Bonsai "value kinds": Input (in the form of a database or csv or whatever), User State (in the form of cells that the user of the Sheet is intended to interactively tweak) and Derived Values (in the form of Formula Cells).
The only real issue with the analogy is that Excel isn't powerful enough to have combinators like assoc
and match%sub
, which is unfortunate, but no analogy is perfect.
Computation.t to Blueprint.t, making it clear that instances of Computation.t are definitions of computations, not computation instances.
Value.t to Computation.t (or Incr_value.t, if we don't want to confuse current Bonsai users), since Value.ts ARE instances of incremental computations. This also avoids confusion with raw OCaml values.
I'll hold off on evaluating these name choices because we've got a few proposals to change how the types themselves work
Proposal #1: Use phantom type(s) to encode the various kinds
type ('a, 'k) t
val state : 'a -> ('a, [`Stateful]) t
val map : ('a, [`Pure]) t -> ('a -> 'b) -> ('b, [`Pure]) t
val arr : ('a, [`Pure]) t -> ('a -> 'b) -> ('b, [`Stateful]) t
val sub : ('a, [`Stateful]) t -> (('a, [`Pure]) t -> ('b, _) t -> ('b, [`Stateful]) t
Proposal #2: Define a "builder" monad
type 'a t
module Expr : Monad.S
val state : 'a -> 'a t Expr.t
val map: 'a t -> ('a -> 'b) -> 'a t
val arr: 'a t -> ('a -> 'b) -> 'b t Expr.t
(* [sub] is basically deprecated in favor of Expr.bind, but you could still have
one and it would look like this *)
val sub: 'a t Expr.t -> ('a t -> 'b t Expr.t) -> 'b t Expr.t
^ with this proposal, bonsai doesn't "become a monad" because for most (all?) Bonsai combinators, the Expr.t
wraps a 'a t
, meaning that you still don't get access to the 'a
inside the scope of the bind.
Single, Unified Platform
Lots to say here, but I agree with a lot of it; but it's largely predicated on having the content for the open-source docs, which is where I think we're most lacking...
Is there a reason why we don't use let punning? It would cut down on visual noise, reducing the "syntax boilerplate" needed to write Bonsai components.
Our internal version of OCaml is old enough that we don't have let-punning yet. This should change, like, next week!
We do have a fairly diverse audience: web devs interested in OCaml, OCaml devs interested in web, Jane Street / Incremental devs who want a nice web UI, etc. Maybe we should have several introductory pages depending on who you are? Maybe this could take the form of a dynamic homepage, leading to the same guide. Alternatively, we could have several short crash courses, which are then expanded on in the main guide. I like the "bonsai for incremental users" article we have now.
I love this idea! I think it might work better if the guide was more "diamond shaped" though: start with some common introductory material; then fork out to comparisons / analogies to other frameworks; then join back in for advanced topics.
We should consider embedding a very complex, probably contrived web UI example on the Bonsai landing page. This would showcase the performance and flexibility implications of Bonsai, and give users an example to play around with.
I'm really bad at coming up with demos, if you have any ideas, I'd love to hear them!
In theory, it should be possible to create an in-browser sandbox (built with Bonsai??? :D). If it's not too slow to be useful, that could both help prototype/review new components, and be a useful learning tool.
Yesssssss! I think Philip actually had a demo of this working last year. I'm actually most interested in using it as a teaching aid for the Bonsai Guide and also other OCaml libraries that could have interactive, editable demos. It would also be a great addition to our component gallery; people could fiddle with options and see them update live!
The "testing" docs seem to be missing; effects has a broken link at the bottom.
Oops, we've definitely published it, but it appears to be at a different location in the github version. I'll try to fix this
I'll hold off on evaluating these name choices because we've got a few proposals to change how the types themselves work
I think one of the biggest learning hurdles for me was understanding Computation
and Value
, what they represent, and how they should be used, especially with let%sub
, let%arr
, and general let
being new syntax. To be honest, I'm still not sure I've fully grasped this, as evidenced by the hodgepodge of analogies I included in this PR. I've come to think of Computation
and Value
as a layer of boilerplate / "chemical glove box", which allows the Bonsai compiler to analyze and optimize the component structure. In my current mental model, Computation
is the structured "shell" of the program, from which the compiler will determine intent and perform optimizations, and Value
is a thin wrapper around the Incr
library used at runtime.
Reading over the proposals made me realize that there's still a key piece I need to confirm. Is the split into Computation
and Value
there only so that we can have both parallel and serial branching, to qualify as an arrow? And if we didn't care about parallel branches (which we do, of course), could we combine Computation
and Value
into one wrapper type, and still be able to perform compiler optimizations?
Thinking through the Excel analogy, we have several types of cells:
Var
, watched as a Value
Value
, derived from other Value
s)Value
wrapped around a constant)match%sub
, assoc
, and Dynamic_scope
state_machinex
, some structural wrapper around it (e.g. state
, of_model
), or stateful utility combinators (e.g. freeze
)The system we have now is built around a Formula
/Blueprint
datatype (Computation
), which defines, and can be instantiated into, incremental computations (Value
). This allows us to share state (by using the same Value.t
), or duplicate stateful components with separate instantiations. This has the added bonus of letting us put all the structural stuff in Computation: type 'result kind
. However, it doesn't exactly map to the "different type of cells" analogy: both a Value
and a Computation
can have state machines.
Finally, the only type of cell that needs to be handled differently w.r.t. branching serially vs in parallel is state cells: everything else could be copied or referenced, and the result would more-or-less be the same.
Assuming I'm understanding this correctly, I'm going to speculate out loud about how these proposals would work:
Proposal #1 would flatten Computation
and Value
into one t
type, which would contain the structure of the web app, and get compiled down to an Incr
computation. Stateful
would be the new Computation
, and Pure
would be Value
. I like that this restructures things in terms of the "user-facing" types of cells, but I worry that it might not be entirely accurate. As with the current Computation
and Value
split, a "stateful" component subgraph could be both Stateful
(before sub
), and Pure
(after sub
), which feels like it would add confusion. I'd like a system where the types describe which kind of cell a computation is, but the way I see things, the reason we need a type division in the first place is to control whether states are cloned vs shared, not whether they exist or not. As you mentioned in "Why should functional programmers be okay with stateful components?", we should expect most of a web UI to have some kind of stateful components. We already have a way to denote entirely pure logic: regular 'a -> 'b
OCaml functions.
Proposal #2 would nest Bonsai.t
(representing the incremental computation) inside of a monadic Expr.t
, instead of juggling Value
and Computation
on the same "depth". I think this would make the "Expr.t
is a builder of Bonsai.t
, which is an incremental computation of 'a
" relationship clearer. It also helps with the naming concerns I had before. Additionally, then we could say "Expr
is a monad around Bonsai.t
which is an arrow", and Other than that, I don't really see a large difference between #2 and what we have now.
Overall I (theoretically) prefer the ergonomics and simplicity of #1, but I worry that the type naming isn't exactly acccurate, which could add confusion. However, if we eventually want to move towards something like it, I'm not sure if it'd be worth doing breaking changes now for minor improvements, when renaming types would be easier to support BC, and would give most of the same benefits.
if the guide was more "diamond shaped" though
And we could generalize it into an arrow-based framework for documentation! :laughing:
It would also be a great addition to our component gallery
And for that of any other library with visualizable components!
Bonsai Docs Feedback (WIP)
WIP: I still have about half the docs left to go through. Wanted to upload this as a draft PR in case I should change my approach.
Hi all! I've put together some feedback for the Bonsai docs in this PR. A lot of it is fairly crude; I'd like to make sure these suggestions are useful before focusing on refined wording or formatting.
I'm proposing some specific wording / structure changes in the pull request itself. This summary has a few more general suggestions relating to platform, naming, web presence, etc.
I’m assuming that the audience for these docs is familiar with web primitives (HTML, CSS, JavaScript), and has learned OCaml syntax. I'm trying not to assume any advanced knowledge in high-octane frontend development or arrow calculus.
Naming Philosophy
One of the larger changes I'm proposing in the accompanying PR is moving away from the "Graph" vs "Output Node" analogy for Computation vs Value in favor of a variety of others, such as:
While writing out my proposed changes, I've often found myself referring to
Computation.t
as a "Computation Blueprint" or "Computation Definition", and toValue.t
as a "Computation Instance". In turn,Value.t
is a wrapper around an incrementally computed "raw value". This is confusing.Assuming I'm understanding all this correctly, I think it would make sense to rename:
Computation.t
toBlueprint.t
, making it clear that instances ofComputation.t
are definitions of computations, not computation instances.Value.t
toComputation.t
(orIncr_value.t
, if we don't want to confuse current Bonsai users), sinceValue.t
s ARE instances of incremental computations. This also avoids confusion with raw OCaml values.Single, Unified Platform
At the moment, docs for OSS Jane Street releases are scattered across several places:
.mli
s, which provide references for library public APIsdocs
folders on GitHub, which contain.mdx
files and are sometimes sub-organized further into "guides", "getting started tutorials", and "blog posts"For new users, digging through a new (and not always intuitive) repository structure to find a starting point can be challenging. I think it might be worthwhile to make a centralized docs presence, which would have a subset of:
README
s, the OSS homepages, and independent homepages. This could include:.mlx
files, which would contain code blocks (with preview), and a little bit of explanatory text. This could be used to teach about common techniques and patterns, or document reusable components.mli
, and maybe generated API docsI suspect it wouldn't be too difficult to write a library that generates static docs sites from a config file, which would run on every OSS release. The docs could then be hosted under
https://opensource.janestreet.com/
. This would:Building a platform like this might be useful for internal users, and shouldn't significantly interrupt existing workflows. For internal usage, it might make sense to combine docs for all projects into a single "mono-doc site", which could help with global docs search and linking across projects. For example, I'm sure
let%...
docs are relevant to many libraries.Minor Miscellaneous Thoughts