编程与软件工程evincarofautumn.blogspot.com
为什么串接式编程值得重视
Why Concatenative Programming Matters
2012 — 2025,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这是 Jon Purdy 2012 年的一篇博客文章,以教程方式介绍 concatenative(连接式/栈式)编程语言:程序由函数的组合构成,参数不显式标出,而是隐含地在栈上传递,作者由此论证这种编程风格在概念上的简洁与优雅。文章偏重概念讲解,更像入门教程,而非用实际案例论证价值的文章。
为什么经久不衰:它是理解 Forth、Factor、Joy 这类栈式语言设计思想及其长期争议(简洁与可读性)的经典入门读物,而 Hacker News 上跨越十余年的讨论本身就成了这个话题的活标本。
HN 评论精选
缺少参数标记造成的栈效果歧义严重损害可读性,栈语言更适合当编译目标而非人写的源语言。
对我来说,栈语言的问题一直在于类型。我发现很难追踪每个词(函数)确切的栈效果,尤其是当这些函数还会压入、弹出并应用那些自身会修改栈的函数时。即使在处理像优化过的 x87 代码这样简单的东西时,我也会给所有 FXCH 等指令加注释,以便跟踪栈上算术表达式的各个部分,因为我试图让多个操作同时进行。是的,我知道 Christopher Diggins 的 Cat 是静态类型的。问题不在于编译器的诊断信息,而在于可读性。在栈语言中,像 'a b c d' 这样简单的表达式也是晦涩的:如果 c 消耗两个参数,用应用式术语就是 d(c(b, a));如果 b 消耗一个而 c 只消耗一个,那就是 d(c(b(a)));如果 d 消耗两个、b 一个、c 不消耗,那就是 d(c, b(a))。这种歧义让我很难读代码,除非我对每个词都烂熟于心。你必须理解一切才能理解任何东西。不幸的是,我怀疑 concatenative 语言的力量正源于这种歧义,因为缺乏具体性给词对栈的操作留下了相当大的灵活性。所以我目前的成熟看法——这篇文章并没有真正改变它,它主要是一篇教程——是栈语言最好作为编译目标,而不是人类书写的源形式。
barrkel查看英文原文
The problem with stack languages for me has always been in typing. I find it difficult to track the exact stack effects of each word (function), particularly if these functions are pushing, popping and applying functions that themselves modify the stack. Even when dealing with something as simple as optimized x87 code, I would annotate all the FXCH etc. to keep track of the bits of the arithmetic expression on the stack, as I tried to keep multiple operations in flight. Yes, I know Christopher Diggins' Cat is statically typed. The problem isn't in compiler diagnostics, it's in readability. In a stack language, an expression as simple as 'a b c d' is cryptic. If c consumes two arguments, in applicative terms it would be d(c(b, a)); if b consumes one argument and c only one, then it would be d(c(b(a))); if d consumes two arguments, b one, and c none, then it would be d(c, b(a)). And this ambiguity makes it very hard for me to read the code unless I'm intimate with all the individual words. You have to understand everything to understand anything. Unfortunately, I suspect that concatenative languages tend to derive their power from this ambiguity, because the lack of specificity leaves considerable flexibility for what the words can do with the stack. So my considered opinion for now - and this article doesn't really change that, it is mostly a tutorial - is that stack languages are best as a compiler target rather than a human source form.
作者以自己设计 Forth 式语言的经历说明:一旦代码变复杂,缺少参数标记就让代码无法自解释,显式标记不可或缺。
这篇文章介绍了 concatenative 语言,但没有解释它们为什么重要。在我的工作中,我发现函数调用参数缺少语法标记是一个毁灭性的缺点。写完一个函数一周后再回来看自己的定义,我要花好几分钟才能弄懂代码。我可以用尽各种技巧,以 Factor 风格的组合子写出最优雅的函数,结果反而更糟。用局部绑定写出来也没帮助:一旦写出嵌套表达式,你就开始失去哪个值被传到哪里去的感觉。……我当时在设计一种带泛型函数的 Forth 式函数式语言,很长时间里我都觉得缺少标记无关紧要,以为不需要确切知道参数去向也能“足够好”地理解代码。这个论点有一定道理,我们也可以做很多事让代码表达它做的事。但有时作者只是必须实现某个东西,技术细节冒了出来,等你去读的时候,代码并不“可读”,你得自己动脑筋搞清楚它在做什么——它不会告诉你。在这些情况下,显式的参数标记是不可或缺的。在 Forth 式语言里,简单的事很美妙优雅。
tailrecursion查看英文原文
This article introduces concatenative langauges, but it doesn't explain why they matter. In my work, I found that the lack of syntactic marking for arguments of function calls is a devastating drawback. Coming back to my own function definitions a week after writing them, I spent minutes unpuzzling the code. I could use every trick and write the function in the most elegant way, using combinators in the style of Factor, and that made it worse. But writing it out with local bindings also didn't help. As soon as you write a nested expression, you start to lose the sense of which values are being passed where. gcd n1 n2 n2 0 = if n1 else n2 n1 n2 mod gcd gcd zero if else "mod" plus swap gcd factorial 1 interval product I was designing a Forth-like functional language with generic functions, and for a long time I felt that the lack of markings didn't matter. I thought that one could understand the code "well enough" without knowing exactly where the arguments were going. There is something to this argument, and there's a lot we can do to make code say what it does. But sometimes the author just had to implement something, and technicalities arose, and when you go to read it, the code doesn't "read" and you have to bring your own intelligence to figure out what it does -- it won't tell you. In these cases, explicit argument marking is indispensable. In Forth-like languages, simple things are wonderful and elegant. There is no other shorter way to write than point-free. And, writing with combinators is satisfying, and it can make the "essence of the function" more evident. But unless you severely constrain your style to ultra short definitions, avoid nested expressions, and use local variables profusely, you're constructing puzzles for yourself. It's almost like the concatenative style is too optimal. You have to back up a step in beauty in order to get a practical tool.
与《Why Functional Programming Matters》相比,本文缺少有说服力的实际例子,难以激发读者去尝试这类语言。
如果这篇文章是对著名的《Why Functional Programming Matters》一文的致敬,那我认为它在很大程度上失败了。那篇 FP 论文每一节都从 FP 能优雅解决的实际编程问题开始,一步步构建解决方案,并展示每一步多么容易理解、扩展和抽象。FP 论文非常有效地让硬核命令式程序员想去尝试 FP,但在我看来,这篇 CP 文章并不能唤起同样的渴望。你应该试着再写一篇,带上一些实际例子。
cromwellian查看英文原文
If this article is a homage to the famous "Why Functional Programming Matters" paper, I think it failed in a major way. The Why FP Programming Matters paper began each section with practical programming problems that FP solved elegantly. It built up the solutions piece by piece and showed at each step, how easy they were to comprehend, extend, and abstract. The FP paper is very effective in making people who are hard core imperative programmers want to try FP. But the CP article here doesn't really IMHO elicit the same desire. You should try writing another one with some practical examples.
亲身尝试 Factor 十年,栈操作的认知负担始终没有消失,说明命名局部变量仍是好主意,但这类语言的概念简洁性依然值得欣赏。
大约十年前我真的努力去接触 Factor。那是个非常令人印象深刻的项目,但我发现操纵栈的认知负担顽固地不肯随时间消退。我说这话是作为一个写中等复杂 Haskell 代码还算自如的人,所以不是我无法适应不寻常的编程范式。我认为命名局部变量结果被证明是个极好的主意。话虽如此,我确实欣赏 concatenative 语言的概念简洁性和易于实现,它们当然有自己的位置。为了公平起见,如果有 Factor 布道者,我要补充:这门语言如果想用,也可以很容易地使用命名变量。
foldr查看英文原文
I really made an effort to get into https://factorcode.org/ about a decade ago. It's an incredibly impressive project, but I found that the cognitive overhead of manipulating the stack stubbornly failed to go away over time. I say this as someone who is reasonably comfortable writing moderately complex Haskell code, so it's not that I'm unable to adjust to unusual programming paradigms. I think naming local variables just turns out to be an incredibly good idea. That said, I do appreciate the conceptual simplicity and ease of implementation of concatenative languages. They certainly have their place. In case there are any Factor evangelists out there, let me add in fairness that the language makes it easy to use named variables if you want to.
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选