TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Exploring biphasic programming: a new approach in language design

125 点作者 chriscbr11 个月前

29 条评论

chubot11 个月前
This is already known as &quot;multi-stage programming&quot; or &quot;staged programming&quot; -- I don&#x27;t see a need for a new term<p><a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Multi-stage_programming" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Multi-stage_programming</a><p><a href="https:&#x2F;&#x2F;okmij.org&#x2F;ftp&#x2F;meta-programming&#x2F;index.html" rel="nofollow">https:&#x2F;&#x2F;okmij.org&#x2F;ftp&#x2F;meta-programming&#x2F;index.html</a><p>Comment from 2019 about it, which mentions Zig, Terra&#x2F;Lua, Scala LMS, etc.:<p><a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=19013437">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=19013437</a><p>We should also mention big data frameworks and ML frameworks like TensorFlow &#x2F; Pytorch.<p>The &quot;eager mode&quot; that Chris Lattner wanted in Swift for ML and Mojo is to actually to get rid of the separation between the stage of creating a graph of operators (in Python, serially) and then evaluating the graph (on GPUs, in parallel).<p>And also CMake&#x2F;Make and even autoconf&#x2F;make and Bazel have stages -- &quot;programming&quot; a graph, and then executing it in parallel:<p><i>Language Design: Staged Execution Models</i> - <a href="https:&#x2F;&#x2F;www.oilshell.org&#x2F;blog&#x2F;2021&#x2F;04&#x2F;build-ci-comments.html#language-design-staged-execution-models" rel="nofollow">https:&#x2F;&#x2F;www.oilshell.org&#x2F;blog&#x2F;2021&#x2F;04&#x2F;build-ci-comments.html...</a>
评论 #40866553 未加载
评论 #40864983 未加载
noelwelsh11 个月前
Like the other comment mentioned, this is staging.<p>&gt; And compared to Lisps like Scheme and Racket which support hygenic macros, well, Zig doesn’t require everything to be a list.<p>This comment is a bit ignorant. Racket has the most advanced staging system of any language that I&#x27;m aware of. You can build languages in Racket with conventional yet extensible syntax: <a href="https:&#x2F;&#x2F;docs.racket-lang.org&#x2F;rhombus&#x2F;index.html" rel="nofollow">https:&#x2F;&#x2F;docs.racket-lang.org&#x2F;rhombus&#x2F;index.html</a> Zig&#x27;s metaprogramming facilities are very simple in comparison.<p>I think staging could be extremely useful in many application, and I wish it was better supported in mainstream langauges.
评论 #40863455 未加载
评论 #40866210 未加载
taliesinb11 个月前
The end-game is just dissolving any distinction between compile-time and run-time. Other examples of dichotomies that could be partially dissolved by similar kinds of universal acid:<p>* dynamic typing vs static typing, a continuum that JIT-ing and compiling attack from either end -- in some sense dynamically typed programs are ALSO statically typed -- with all function types are being dependent function types and all value types being sum types. After all, a term of a dependent sum, a dependent pair, <i>is</i> just a boxed value.<p>* monomorphisation vs polymorphism-via-vtables&#x2F;interfaces&#x2F;protocols, which trade roughly speaking instruction cache density for data cache density<p>* RC vs GC vs heap allocation via compiler-assisted proof of memory ownership relationships of how this is supposed to happen<p>* privileging the stack and instruction pointer rather than making this kind of transient program state a first-class data structure like any other, to enable implementing your own co-routines and whatever else. an analogous situation: Zig deciding that memory allocation should NOT be so privileged as to be an &quot;invisible facility&quot; one assumes is global.<p>* privileging <i>pointers</i> themselves as a global type constructor rather than as typeclasses. we could have pointer-using functions that transparently monomorphize in more efficient ways when you happen to know how many items you need and how they can be accessed, owned, allocated, and de-allocated. global heap pointers waste <i>so</i> much space.<p>Instead, one would have code for which it makes more or less sense to spend time optimizing in ways that privilege memory usage, execution efficiency, instruction density, clarity of denotational semantics, etc, etc, etc.<p>Currently, we have these weird siloed ways of doing <i>certain</i> kinds of privileging in <i>certain</i> languages with rather arbitrary boundaries for how far you can go. I hope one day we have languages that just dissolve all of this decision making and engineering into universal facilities in which the language can be anything you need it to be -- it&#x27;s just a neutral substrate for expressing computation and how you want to produce machine artifacts that can be run in various ways.<p>Presumably a future language like this, if it ever exists, would descend from one of today&#x27;s proof assistants.
评论 #40861409 未加载
评论 #40863076 未加载
评论 #40873642 未加载
pmontra11 个月前
A question to the author, about a choice in language design.<p><pre><code> &#x2F;&#x2F; Import some libraries. bring s3; </code></pre> If the keyword was the usual &quot;import&quot; there would be no need to explain what &quot;bring&quot; is. Or, if &quot;bring&quot; is so good, why not<p><pre><code> &#x2F;&#x2F; Bring some libraries. ?</code></pre>
评论 #40866320 未加载
funcDropShadow11 个月前
This is also a special case of what MetaOCaml calls multi-stage programming. It does not only support two phases but arbitrary many. Some similar prototype also exists for some older Scala version. And Lisp and Forth obviously also support n-phases of computation.
warpspin11 个月前
He missed one of the earliest examples of &quot;languages and frameworks that enable identical syntax to express computations executed in two distinct phases&quot; - immediate words in Forth: <a href="https:&#x2F;&#x2F;www.forth.com&#x2F;starting-forth&#x2F;11-forth-compiler-defining-words&#x2F;" rel="nofollow">https:&#x2F;&#x2F;www.forth.com&#x2F;starting-forth&#x2F;11-forth-compiler-defin...</a>
评论 #40860565 未加载
评论 #40860198 未加载
cb32111 个月前
Nim &amp; D also have the compile-time function evaluation he mentions for Zig. Nim also has a full macro system wherein macros are written in Nim - just taking &amp; producing ASTs. I&#x27;ve known people to refer to this&#x2F;Julia macro systems as &quot;homoiconic&quot;. Nim also has a javascript backend to enable similar same-syntax on client&amp;server like his React &amp; clojure examples.
cobbal11 个月前
Racket has a sophisticated system for dealing with phases in its macro system: <a href="https:&#x2F;&#x2F;docs.racket-lang.org&#x2F;guide&#x2F;phases.html" rel="nofollow">https:&#x2F;&#x2F;docs.racket-lang.org&#x2F;guide&#x2F;phases.html</a> I don&#x27;t know if other schemes use a similar system.
thelittlenag11 个月前
I&#x27;ve been thinking similar thoughts recently since I&#x27;ve been exploring metaprogramming in Scala and how it can be extended to beyond the simplistic hygenic model it currently supports.<p>What I recently realized is that while compilers in the standard perspective process a language into an AST, do some transformations, and then output some kind of executable, from another perspective they are really no different than interpreters for a DSL.<p>There tends to be this big divide between what we call a compiler and what we call an interpreter. And we classify languages as being either interpreted or compiled.<p>But what I realized, as I&#x27;m sure many others have before me, is that that distinction is very thin.<p>What I mean is this: from a certain perspective a compiler is really just an interpreter for the meta language that encodes and hosts the compiled language. The meta-language directs the compiler, generally via statements, to synthesize blocks of code, create classes with particular shapes, and eventually write out certain files. These meta-languages don&#x27;t support functions, or control flow, or variables, in fact they are entirely declarative languages. And yet they are the same as the normal language being compiled.<p>To a certain degree I think the biphasic model captures this distinction well. Our execution&#x2F;compilation models for languages don&#x27;t tend to capture and differentiate interpreter+script from os+compiled-binary very well. Or where they do they tend to make metaprogramming very difficult. I think finding a way to unify those notions will help languages if and when they add support for metaprogramming.
评论 #40863032 未加载
EricRiese11 个月前
Raku has this<p><a href="https:&#x2F;&#x2F;docs.raku.org&#x2F;language&#x2F;phasers" rel="nofollow">https:&#x2F;&#x2F;docs.raku.org&#x2F;language&#x2F;phasers</a><p>It has many more than 2 phases.<p>Phasers is one of the ideas Raku takes as pretty core and really runs with it. So in addition to compile time programming, it has phasers for run time events like catching exceptions and one that&#x27;s equivalent to the defer keyboard in several languages.
graypegg11 个月前
I wonder if something like Ruby could fit into this category too, even though there isn’t a clean line between the two phases. (I’m stretching the concept a bit heh)<p>The block inside of a class or module definition is executed first, and then the application can work on the resulting structure generated after that pass. Sorbet (a Ruby static typing library) uses this first-pass to generate its type metadata, without running application code. (I think by stubbing the class and module classes themselves?)
StiffFreeze911 个月前
Other &quot;biphasic&quot;-like aspects of programming languages and code:<p>- Documentation generated from inline code comments (Knuth&#x27;s literate programming)<p>- Test code<p>We could expand to<p>- security (beyond perl taint)<p>- O(n) runtime and memory analysis<p>- parallelism or clustering<p>- latency budgets<p>And for those academically inclined, formal language semantics like <a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Denotational_semantics" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Denotational_semantics</a> versus operational and others..
gsuuon11 个月前
My toy language project is also built around multi-stage (though the way it&#x27;s formed it&#x27;s more like literate programming) and partly motivated by writing cloud-native applications. I played around with a sketch of this idea implemented using F# computation expressions[1] and partly implemented an Azure backend, at a high level it appears pretty similar to Winglang. When run at &quot;comptime&quot; &#x2F; CLI, it spins up those resources if necessary and then produces artifacts via msbuild task for servers that run the &quot;runtime&quot; part of the code. The computation expression handles exposing a client and forming the ARM template based on the context. It gets around the inflight&#x2F;preflight distinction by including the entire app (including provisioning stuff) in each runtime instance, so references outside of route scopes work (instance-globally, not app-globally).<p>Very excited for multi-stage - especially it&#x27;s potential to provide very good LSP&#x2F;diagnostics for library users (and authors). It&#x27;s hard to provide good error messages from libraries for static errors that are hard to represent in the type system, so sometimes a library user sees vague&#x2F;unrelated errors.<p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;gsuuon&#x2F;kita&#x2F;blob&#x2F;d741c0519914369da9c89241df283581dbe9c5fd&#x2F;tests&#x2F;Kita.Providers.Azure.Test&#x2F;App&#x2F;App.fs#L79">https:&#x2F;&#x2F;github.com&#x2F;gsuuon&#x2F;kita&#x2F;blob&#x2F;d741c0519914369da9c89241...</a>
kragen11 个月前
this &#x27;biphasic programming&#x27; thing is item #9 in pg&#x27;s list of &#x27;what made lisp different&#x27; from 02001: <a href="https:&#x2F;&#x2F;paulgraham.com&#x2F;diff.html" rel="nofollow">https:&#x2F;&#x2F;paulgraham.com&#x2F;diff.html</a><p>it&#x27;s interesting to read this biphasic programming article in the context of pg&#x27;s tendentious reading of programming language history<p>&gt; <i>Over time, the default language, embodied in a succession of popular languages, has gradually evolved toward Lisp. 1-5 are now widespread. 6 is starting to appear in the mainstream. Python has a form of 7, though there doesn&#x27;t seem to be any syntax for it. 8, which (with 9) is what makes Lisp macros possible, is so far still unique to Lisp, perhaps because (a) it requires those parens, or something just as bad, and (b) if you add that final increment of power, you can no longer claim to have invented a new language, but only to have designed a new dialect of Lisp ; -)</i><p>it of course isn&#x27;t <i>absolutely</i> unique to lisp; forth also has it<p>i think the academic concept of &#x27;staged programming&#x27; <a href="https:&#x2F;&#x2F;scholar.google.com&#x2F;scholar?cites=2747410401001453059&amp;as_sdt=2005&amp;sciodt=0,5&amp;hl=es" rel="nofollow">https:&#x2F;&#x2F;scholar.google.com&#x2F;scholar?cites=2747410401001453059...</a> is a generalization of this, and partial evaluation is a very general way to blur the lines between compile time and run time
评论 #40862424 未加载
jalk11 个月前
&quot;Biphasic programming&quot; is also present in frameworks like Apache Spark, Tensorflow, build tools like Gradle and code-first workflow engines. Execution of the first phase generates a DAG of code to be executed later. IMO the hardest thing for newcomers is when phase 1 and phase 2 code is interleaved with no immediate clear boundaries, (phase 1 code resembles an internal DSL). The docs need to teach this early on to avoid confusion. A prime offender of this is SBT, with its (perhaps no longer true) 3 stage rocket, which is not really described in the docs (see <a href="https:&#x2F;&#x2F;www.lihaoyi.com&#x2F;post&#x2F;SowhatswrongwithSBT.html#too-many-layers-of-interpretation" rel="nofollow">https:&#x2F;&#x2F;www.lihaoyi.com&#x2F;post&#x2F;SowhatswrongwithSBT.html#too-ma...</a>)
a1o11 个月前
I don&#x27;t get the dismissal of C++, to me constexpr is exactly that! And now if we get reflection in C++26 it will be possible to do even more incredible things using it, but constexpr is already pretty good.
评论 #40861505 未加载
mikewarot11 个月前
Since we&#x27;re going down the road of interesting ideas, let&#x27;s add declarative programming to the mix<p>The Metamine language allowed for a <i>magic equals := if I recall correctly</i>, which had the effect of always updating the result anytime the assigned value changed for the rest of the life of the program. Mixing it with normal assignments and code made for some interesting capabilities.
m7zA3qHjoppS11 个月前
Another versions of this can be found in guix, called G-Expressions [0]. This is one of the reasons I like guix vs nix, as it allows you to write the package declarations and things like build steps [1] or even service definitions [2] in the same language.<p>[0] <a href="https:&#x2F;&#x2F;guix.gnu.org&#x2F;manual&#x2F;en&#x2F;html_node&#x2F;G_002dExpressions.html" rel="nofollow">https:&#x2F;&#x2F;guix.gnu.org&#x2F;manual&#x2F;en&#x2F;html_node&#x2F;G_002dExpressions.h...</a> [1] <a href="https:&#x2F;&#x2F;guix.gnu.org&#x2F;manual&#x2F;en&#x2F;html_node&#x2F;Build-Phases.html#index-build-phases_002c-customizing" rel="nofollow">https:&#x2F;&#x2F;guix.gnu.org&#x2F;manual&#x2F;en&#x2F;html_node&#x2F;Build-Phases.html#i...</a> [2] <a href="https:&#x2F;&#x2F;guix.gnu.org&#x2F;manual&#x2F;en&#x2F;html_node&#x2F;Shepherd-Services.html#index-shepherd_002dconfiguration_002daction" rel="nofollow">https:&#x2F;&#x2F;guix.gnu.org&#x2F;manual&#x2F;en&#x2F;html_node&#x2F;Shepherd-Services.h...</a>
ithkuil11 个月前
Also interesting is the singeli language <a href="https:&#x2F;&#x2F;github.com&#x2F;mlochbaum&#x2F;Singeli&#x2F;tree&#x2F;master">https:&#x2F;&#x2F;github.com&#x2F;mlochbaum&#x2F;Singeli&#x2F;tree&#x2F;master</a>
JonChesterfield11 个月前
I&#x27;m pretty sure staged programming is a design mistake induced by the capabilities of computers in the ~70s. Needing to pay attention to which parts of a program have already been compiled and which haven&#x27;t is totally orthogonal to whatever problem you&#x27;re trying to solve with the computer. It&#x27;s going to go the way of manual memory management.<p>The implementation shall be JIT compiled with a separate linter running in the editor for that is the right thing.<p>We aren&#x27;t there yet but I believe it&#x27;s where we&#x27;ll end up.
zamalek11 个月前
For what its worth I like the function coloring Rust has, I don&#x27;t believe compilation results should vary across separate runs. It&#x27;s the same spirit as the rest of the language: highly predictable. The likes of diesel are very cool, but still amount to a big fat &quot;yikes&quot; from me.<p>I think the actual problem is the glacial pace of applying it, and the lack of support in trait impls (e.g. i32.min) and syntax. If it were applied to every pure fn+syntax it would probably cover a great deal of what Zig is doing.
AlexErrant11 个月前
Another example of biphasic programming is parser generators with DSLs for generating parsers, e.g. Tree Sitter or Lezer.
评论 #40866317 未加载
hbbio11 个月前
Funny to see the example of RSC in that context!<p>Multi-stage programming and distribution with the same syntax between clients and servers has been _the_ key feature of Opa (opalang.org) 15 years back. Funny because Opa was a key inspiration for React and its JSX syntax but it took a lot of time to match the rest of the features.
indyjo11 个月前
Would embedding code (which is executed by some other runtime, like SQL, shaders, compute kernels etc.) also be considered &quot;biphasic&quot; or &quot;multi-stage&quot; programming?
Svoka11 个月前
To be honest `comptime` seems excessive. Like, if something can be calculated at compile time, it should be. Why the extra keywords for that? Rust is mostly doing it already.
评论 #40860634 未加载
评论 #40860676 未加载
评论 #40866353 未加载
williamcotton11 个月前
I like the term biphasic! The prior terms for this with Javascript web development were &quot;isomorphic&quot; or &quot;universal&quot;. I don&#x27;t think these ever really caught on.<p>I&#x27;ve been rendering the same React components on the server and browser side for close to decade and I&#x27;ve come across some really good patterns that I don&#x27;t really see anywhere else.<p>Here&#x27;s the architectural pattern that I use for my own personal projects. For fun I&#x27;ve starting writing it in F# and using Fable to compile to JS:<p><a href="https:&#x2F;&#x2F;fex-template.fly.dev" rel="nofollow">https:&#x2F;&#x2F;fex-template.fly.dev</a><p>A foundational element is a port of express to the browser, aptly named browser express:<p><a href="https:&#x2F;&#x2F;github.com&#x2F;williamcotton&#x2F;browser-express">https:&#x2F;&#x2F;github.com&#x2F;williamcotton&#x2F;browser-express</a><p>With this you write not only biphasic UI components but also route handlers. In my opinion and through lots of experience with other React frameworks this is far superior to approaches taken by the mainstream frameworks and even how the React developers expect their tool to be used. One great side effect is that the site works the same with Javascript enabled. This also means the time to interaction is immediate.<p>It keeps a focus on the request itself with a mock HTTP request created from click and form post events in the browser. It properly architects around middleware that processes an incoming request and outgoing response, with parallel middleware for either the browser or server runtime. It uses web and browser native concepts like links and forms to handle user input instead of doubling the state handling of the browser with controlled forms in React. I can&#x27;t help but notice that React is starting to move away from controlled forms. They have finally realized that this design was a mistake.<p>Because the code is written in this biphasic manner and the runtime context is injected it avoids any sort of conditionals around browser or server runtime. In my opinion it is a leaky abstraction to mark a file as &quot;use client&quot; or &quot;use server&quot;.<p>Anyways, I enjoyed the article and I plan on using this term in practice!
JamesBarney11 个月前
As a Microsoft fanboy I have to list our their biphasic additions.<p>Linq. Have a a set of collection manipulation methods that could be run in c# or transformed in SQL.<p>Blazor. Have components that can run on the server, or in the browser, or several other rendering tactics.
z5h11 个月前
Take a look at term_expansion and goal_expansion in the Prologs that support them.
ceving11 个月前
&gt; macro systems like those in C, C++, and Rust<p>Suggesting that the macros of C and Rust may be the same is an insane failure.<p>BTW: meta-programming means &quot;code which generates code&quot; and not &quot;code which runs earlier than other code&quot;.