30 秒でわかる
Ty Overby joins Ron Minsky to explain Bonsai, Jane Street's OCaml library for interactive interfaces. They trace its roots in Elm and Incr_dom, explore state machines, incremental graphs and compiler-style optimization, and discuss CSS, browser limitations, Excel and Blender.
- 1From boilerplate to BonsaiBonsai packages state, actions and incremental computations into composable components, reducing the work that encouraged monolithic interfaces.
- 2A graph rather than a view treeA component can produce an arbitrary value that flows into another component, independent of the eventual DOM hierarchy.
- 3A framework that optimizes its graphKnowing possible component structure ahead of time allows compiler-style optimization and could support graph-aware debugging.
- 4Preventing CSS collisionsAn OCaml extension assigns unique names to component styles, though it does not eliminate the complexity of browser layout.
- 5Inspect the computation beside its resultExcel and Blender show how direct access to formulas and intermediate results can make programming more approachable.
ポイント
- Explicit actions and state transitions make it easier to reason about user interaction and edge cases.
- Incremental computation can reuse work when only small parts of an interface change.
- Bonsai makes computations composable as a graph, including components that produce values rather than views.
- A graph known ahead of time enables optimization and potential debugging tools, at the cost of some runtime flexibility.
- CSS name isolation helps components compose, while browser layout remains a separate challenge.
- Excel and Blender make computations approachable by placing results close to the operations that produce them.
チャプターごとに整えた全文を読む
From Neopets to programmatic CAD
Overby describes his background and compares functional representations of 3D shapes with boundary meshes.
Ron Minsky introduces Ty Overby, a Jane Street software engineer who designed Bonsai, an OCaml library for building interactive web interfaces. Overby's web work began with Neopets pages in middle school; he later studied at the University of Washington and worked on compilers at Microsoft.
Overby says a recurring theme in his hobby projects is applying compiler techniques to other problems. One long-running project is a programmatic computer-aided design system: shapes are described by functions from points in space to a measure of distance from their boundaries.
Minsky explains that programmatic CAD uses code to describe a 3D object rather than constructing it only through a graphical editor. OpenSCAD is one example. Overby contrasts boundary representations, built from elements such as points and faces, with functional or implicit representations, where a function defines a surface.
In an implicit representation, the zero set of a function can describe the boundary. Overby likes how simple combinators can combine or cut shapes and how directly a mathematical function can produce a shape, such as an interference pattern clipped by a circle. Minsky notes that boundary-based systems can also be programmed, though the styles differ.
Minsky notes that a polygonal approximation often requires choosing a resolution early, and combining meshes can produce artifacts. An implicit form can keep the mathematical description until final rendering. Overby adds that converting it to a boundary mesh for 3D printing or a game engine is difficult, especially for unusual topology; he praises Matt Keeter's libfive while acknowledging its edge cases.
Elm, Incr_dom and state machines
The Elm architecture separates models, views and actions. Incremental computation supports responsive interfaces but can complicate composition.
Before Jane Street, Overby had also worked on an in-browser REPL at Microsoft. At Jane Street he encountered Incr_dom, a UI library built on js_of_ocaml, which compiles OCaml into JavaScript. The company had built real interfaces with it, but also encountered limitations.
Overby starts with the Elm architecture. A view function takes application inputs and a model and returns a pure representation of the view. An action function takes the current model and an action from a user or external event and produces the next model, after which the view is recomputed.
Minsky relates this to model-view-controller and React's pure representation of a desired DOM. Overby notes that React has often used state-management libraries to handle functional model updates; local component state can disappear when a component leaves the tree and is added again.
In the Elm-style account, the UI is a pure function from immutable model data to view data, with actions describing how events change the model. Overby says the more interesting part is not simply generating a view, but designing well-defined transitions so interactions behave sensibly in edge cases.
A state machine separates state, actions, and the function that produces the next state. Because actions are explicit, a program can recognize related events and apply guardrails, such as debouncing a double click or fast repeated input, rather than scattering direct mutations across handlers.
Incr_dom adopted much of the Elm pattern and combined it with Jane Street's Incremental library. Incremental computation can reuse work when inputs change only slightly and only a small part of the output changes. Minsky observes that responsive interfaces generally need some form of incrementalization because users typically change only a small part of a view at once.
Overby explains that Incr_dom also computes action-application functions incrementally. That lets data flow through the application into both view and state-transition logic, but composing components means composing their action handlers as well as their views, producing substantial boilerplate.
A large table illustrates the benefit: it may sort, filter, and display hundreds of thousands of rows while putting only a small visible subset in the DOM. Intermediate sorted and filtered structures can also support keyboard row selection without repeating the same work, because the action function can share incrementally computed data.
The cost was composability. Overby recalls a minimal combinator for two Incr_dom components taking roughly 50 to 70 lines to split models, dispatch actions, and combine views. The tedious and error-prone recombination discouraged developers from splitting applications into reusable pieces.
Bonsai's composable graph
Bonsai packages incremental state machines and lets computations produce arbitrary values. Its graph separates component dependencies from the view tree.
Bonsai began as a type capturing the pattern for an Incr_dom component: a computation that produces a view, useful downstream data, and an action handler from a model and a means of raising events. Combinators could then package the repetitive work of combining models and handlers.
Overby soon removed the requirement that a component produce a view. A Bonsai component can instead produce any incrementally computed result. Many components he writes are state machines that yield values used by other components, with a view perhaps created only later.
Bonsai organizes computations as a directed acyclic graph rather than tying component structure to a view tree. This lets a value from one component become an input to another. Overby contrasts that with the tree-oriented React style, where information often travels through a common parent or other workarounds.
For example, a button might be enabled only when a text box contains text. In a tree-oriented arrangement, the parent can receive a callback from the text box and pass a disabled value to the button. A graph-oriented computation can make the button depend directly on the text value without making it a child of the text box.
Bonsai computations expose the value they produce without exposing their internal model or action types. Minsky describes this as compartmentalizing functions and state machines while providing a way to compose both. Overby sometimes calls Bonsai a framework for building incremental state machines.
Could Bonsai work outside web UIs? Overby expects it to apply to other interfaces if there is a pure value representing the desired view, although he has not found a compelling non-UI example. Mutation-based native UI libraries would require an appropriate abstraction, and side effects inside computations can make reasoning difficult.
A compiler for interfaces
A known computation graph supports optimization and potential debugging. Syntax extensions help users write in this staged model.
Bonsai is also a compiler project. Its component graph is constrained so that its possible structure is known once the application has been constructed. Treating the graph as a program makes optimizations possible, including constant folding, combining cheap nodes, and choosing suitable incremental algorithms for particular map-like operations.
The optimization step runs when the application starts: the user supplies a Bonsai computation, the framework traverses and optimizes its representation, and then it starts running. Minsky compares that representation to an abstract syntax tree; Overby calls it an unevaluated expression.
Overby describes three layers: OCaml as a metalanguage assembles the component graph; Bonsai supplies constructs such as conditionals, recursion, functions, and application; and ordinary OCaml expresses the runtime business logic inside components. After the first stage, runtime logic cannot add new possibilities to the graph.
A static graph does not mean a static interface. An email application can switch among inbox, compose, and message views at runtime, as long as those possible subgraphs are known to the framework beforehand. The constraint trades some dynamic freedom for optimization and other services.
One prospective service is a debugger that knows the application's structure in advance and lets a developer navigate the graph, inspect values, and examine component state. Overby is clear that he had talked about building it but had not yet done so.
Minsky asks whether the abstract machinery makes Bonsai difficult to learn. Overby says the learning curve is improving but remains imperfect; an early class of around 50 people exposed many frustrations. OCaml syntax extensions help make Bonsai expressions resemble familiar OCaml constructs such as let, if, and match.
The speakers discuss metaprogramming more broadly. Familiar syntax can make monadic libraries usable without first mastering the theory, while macros can simplify repetitive expressions. They also have costs: complex transformations can be difficult to reason about and produce awkward errors.
Overby and Minsky consider OCaml's macro facilities useful but imperfect. Compiler extensions can inject arbitrary code, yet small local extensions are awkward, and their use is largely controlled by the build system. They would like more modular support for macros.
Adoption, CSS and OCaml on the web
Compatibility helped adoption, while namespacing styles and reducing verbosity remained challenges. Jane Street's internal web environment has unusual constraints.
For adoption, Overby values compatibility with existing Incremental programs: teams could introduce Bonsai gradually and compare the new code with what they maintained already. At the time, he knew of no serious new internal project avoiding Bonsai. He also curates examples and promotes reusable components written by colleagues.
One remaining problem is CSS composition. Independently developed components can ship class names that collide and override one another. Inline styles avoid some clashes, but CSS also offers useful selectors and behaviors, such as alternating table rows and hover styling.
Overby describes an OCaml extension in progress that extracts CSS written in the source file, gives its names unique hashes based on the content and filename, and exposes the resulting names to OCaml. This targets accidental collisions; it does not solve the separate difficulty of browser layout and interacting style rules.
Another frustration is repeated names when moving between Bonsai's component language and runtime OCaml code. He hopes OCaml's newer let-punning feature will reduce the verbosity when a binding and its value share a name.
Asked about OCaml on the web, Overby cautions that Jane Street has unusual conditions. Fast networks and long-running internal single-page applications make large JavaScript bundles, absent server-side rendering, and limited code splitting less damaging than they would be for many public websites.
For Jane Street the browser is largely a place to run an OCaml program that generates a UI and maintains a WebSocket connection. Overby finds OCaml well suited to immutable programming and says his strongest remaining complaints tend to come from the library author's perspective.
The browser and other UI tools
The speakers consider the DOM, canvas, WebAssembly and Svelte. They discuss which browser capabilities UI authors would like to control.
On the wider web platform, Overby notes that JavaScript and the DOM were the dominant language and UI runtime. He hopes WebAssembly may eventually broaden language options, including support needed for OCaml's garbage collector. He also values the DOM's accessibility and styling facilities.
His wish is more control over layout and rendering for unusual components while retaining the useful machinery of the browser. Drawing everything on a canvas provides flexibility but forces developers to rebuild difficult features such as text selection, cursor movement, text shaping, and layout.
Overby imagines deeper APIs for the layout engine, 2D renderer, and keyboard and mouse events. He mentions the Houdini proposals as work in this direction, while acknowledging uncertainty at the time about standardization, availability, and capabilities.
Among other UI tools, Overby admires Svelte's use of a compiler to analyze components ahead of time, optimize them, and identify some mistakes. He notes that his impression comes from reading tutorials rather than actually programming in Svelte.
Excel, Blender and visual programming
Excel and Blender connect computations with visible results. Overby argues that inspection and debugging are central to visual programming.
Overby is skeptical that purely graphical UI builders can expose enough power for every developer without strong hooks or a path into code. Minsky offers Excel as a remarkably successful interface-building system, and Overby calls it arguably the greatest programming language: people program in it without necessarily thinking of themselves as programmers.
Excel combines data entry, visualization, and analysis with an incremental framework that avoids unnecessary recomputation. Minsky praises the experience within the formula language's limits while noting serious imperfections, including cases where genomic identifiers were interpreted as dates.
For Overby, Excel's power comes partly from the short distance between a displayed result and the formula that produced it. A user can click a cell and inspect the computation rather than searching through source code. He sees a related strength in Blender's node-based shader editor.
In Blender, nodes represent operations on numbers, colors, and textures. They can be combined visually, and intermediate outputs can be previewed. Overby finds this essential for building effects that would be very hard for him to write as source code without seeing the intermediate stages.
A shortcut can show the output of one selected node, and a plugin can display previews beside multiple nodes. Minsky describes this as a particularly effective debugger: with visual transformations, an error may merely look wrong, so inspecting intermediate images is more useful than ordinary textual debugging.
Overby says a test cannot simply decide whether a shader looks good; a person must inspect and adjust it. For him, inspectability and debugging are central to visual programming, and Blender, like Excel, empowers people to program without necessarily identifying themselves as programmers.
同じチャンネルの記事
1:48:29EN
1:36:37EN
1:05:45EN
1:25:00EN
1:16:29EN
27:39EN