Jinser Kafka › translations [jsr-000N]

翻译文章的列表,标记的时间是翻译时间。

Translation. Simple but Powerful Pratt Parsing [jsr-0017]

tips: Click on the translation to expand and view the original text. 点击译文可展开查看原文。
Translated according to the version last updated on Apr 13, 2020.
根据2020年4月13日更新的版本翻译。

欢迎阅读我关于 Pratt 解析的文章——语法分析的 monad 教程。关于 Pratt 解析的文章数量如此之多,以至于还有一篇概览文章 :)
Welcome to my article about Pratt parsing — the monad tutorial of syntactic analysis. The number of Pratt parsing articles is so large that there exists a survey post :)

本文的目标:
The goals of this particular article are:

  • 提出一个问题:所谓的左递归问题被夸大了。
  • 抱怨 BNF(巴科斯-瑙尔范式)在表达中缀表达式方面的不足。
  • 提供对 Pratt 解析算法的描述和实现,坚持核心概念,没有引入类似 DSL 的抽象。
  • 希望让自己最后一次试图理解这个算法。我曾经实现过一个生产级的 Pratt 解析器,但我现在不再能立即理解那段代码了 :-)
Raising an issue that the so-called left-recursion problem is overstated.
Complaining about inadequacy of BNF for representing infix expressions.
Providing a description and implementation of Pratt parsing algorithm which sticks to the core and doesn’t introduce a DSL-y abstraction.
Understanding the algorithm myself for hopefully the last time. I’ve implemented a production-grade Pratt parser once, but I no longer immediately understand that code :-)

本文假设读者对解析技术有一定的了解,例如,不会在这里解释 上下文无关文法 ( context free grammar ) 是什么。
This post assumes a fair bit of familiarity with parsing techniques, and, for example, does not explain what a context free grammar is.

Translation. Partial evaluation in guile [jsr-0015]

tips: Click on the translation to expand and view the original text. 点击译文可展开查看原文。
Translated according to the version last updated on 11 October 2011 10:01 AM.
根据2011年10月11日上午10:01更新的版本翻译。

朋友们,就在刚刚发生了一件很棒的事情:Guile 获得了一个值得尊敬的 内联器 ( inliner )
Friends, something awesome just happened: Guile just got itself a respectable inliner.

我以前在这个博客说过,引用评论者 Rémi Forax 的话说,“内联是所有优化之母”。的确如此,内联为代码移动,常量折叠,死代码消除,循环优化开辟了空间。然而,功劳可能更应该归功于 部分求值 ( partial evaluation ) ,这位所有内联优化之母。
I have said before on this blog, quoting commenter Rémi Forax, that "inlining is the mother of all optimizations". It is true that inlining opens up space for code motion, constant folding, dead code elimination, and loop optimizations. However, credit might be better laid at the feet of partial evaluation, the mother of all inlining algorithms.

部分求值是一种源到源的转换,它接收你的程序并产生一个更好的程序:其中任何可以在编译时完成的计算都已完成,只留下那些需要在运行时进行的计算。
Partial evaluation is a source-to-source transformation that takes your program and produces a better one: one in which any computation that can be done at compile-time is already made, leaving only those computations that need to happen at run-time.

例如,这个应用
For example, the application

(+ 2 3)

可以明确地在编译时求值。我们说源表达式 (+ 2 3) 通过常数折叠简化为 5,得到的结果(在这个情况下是 5)是 留存 ( residual ) 表达式。
can clearly be evaluated at compile-time. We say that the source expression (+ 2 3) reduces to 5 via constant folding. The result, 5 in this case, is the residual expression.

一个更复杂的例子:
A more complicated example would look like:

(let ((string->chars
       (lambda (s)
         (define char-at
           (lambda (n) (string-ref s n)))
         (define len
           (lambda () (string-length s)))
         (let loop ((i 0))
           (if (< i (len))
               (cons (char-at i)
                     (loop (1+ i)))
               '())))))
  (string->chars "yo"))
=> (list #\y #\o)

当我在这里写下 =>,你应该将它读作“ 在编译时留存 ( residualizes at compile-time to ) ”。在这里,我们的输入程序在编译时留存为一个简单的 list 构造。循环完全被 展开 ( unrolled ) ,字符串引用折叠,所有 叶子过程 ( leaf procedures ) 都被内联。
Here when I write =>, you should read it as, "residualizes at compile-time to". In this case our input program residualized, at compile-time, to a simple list construction. The loop was totally unrolled, the string-refs folded, and all leaf procedures were inlined.

很棒吧?
Neat, eh?

我似乎离题了,不好意思!
It seems I have digressed. Sorry about that!

我谈到了闭包和词法作用域,这是可以实现静态内联的 JS 语言属性。JavaScript 实现支持内联的第二种(同时更重要的)方式是动态内联。几个月前我用这个问题 钓鱼 ( trolled ) 。当动态内联工作时,它非常棒,尽管有一些条件限制了启发式方式(向下滚动到“inlining”,注意在这几个月中具体的启发式集合已经变化了。)。
I spoke about closures and lexical scope, properties of the JS language that can enable static inlining. The second (and more important) way that JS implementations can support inlining is dynamically. I trolled about that some months ago. Dynamic inlining is fantastic, when it works, though there are limiting heuristics (scroll down to "inlining", and note that the exact set of heuristics have changed in the intervening months).

所以我的最后一点是关于 Guile 表现出色,而 JS 实现表现不佳的事,出于公平起见,我们现在谈一个相反的点。我希望能够实现动态内联,但这意味着要将中间表示与 scheme 函数关联起来。由于 Guile 能够 提前编译 ( ahead-of-time ) 代码,这意味着我们将不得不将中间表示序列化到磁盘上,就像 GCC 的新 链接时优化器 ( link-time optimizer ) (LTO)做的那样。但我希望这个实现推迟到之后我们将编译后 Guile 的格式更改为 ELF,否则我们会有运行时内存大小膨胀的风险。
So my last point was about something that Guile does well that JS implementations do poorly, and it's fair that this point should be the reverse. I would like to be able to dynamically inline, but this would mean associating the intermediate representation with Scheme functions. As Guile can compile code ahead-of-time, this means we would have to serialize the IR out to disk, in much the same way as GCC's new link-time optimizer (LTO) does. But I would like to put that off until we change the format of compiled Guile code to be ELF. Otherwise we run the risk of bloating our runtime memory size.

Translation. Python Negatypes [jsr-0014]

tips: Click on the translation to expand and view the original text. 点击译文可展开查看原文。
Translated according to the version last updated on Sep 26, 2019.
根据2019年9月26日更新的版本翻译。

Translation. Grasping `all-the-apples-at-once' [jsr-000U]

tips: Click on the translation to expand and view the original text. 点击译文可展开查看原文。
Translated according to the version last updated on June 3, 2024.
根据2024年6月3日更新的版本翻译。

Translation. Using zippers to handle huge trees [jsr-000Q]

tips: Click on the translation to expand and view the original text. 点击译文可展开查看原文。有修复原文 typo。

嗨,
Bonjour,

2003年4月9日星期三,Yang Shouxun 写道:
我不知道如何编写尾递归版本来构建树。如果连续属性不多且数据集也不是很大,那树会在堆栈溢出之前停止生长。
(译者按:连续属性是指其在数据集中可以取无限多值,通常是实数,例如身高、温度等。)
On Wednesday, 09 Apr 2003, Yang Shouxun wrote:

> I don't know how to write a tail recursive version to build trees.
> If there are not that many continuous attributes and the dataset is
> not so large, the tree stops growing before stack overflow.

2003 年 4 月 9 日星期三,Markus Mottl 写道:
这里的诀窍是使用延续传递风格(CPS):传递一个包含后续计算所需的所有内容的函数闭包(延续)。子函数不返回结果,而是使用结果调用延续,这使得函数成为尾递归。
On Wednesday 09 April 2003, Markus Mottl wrote:

> The trick is to use continuation passing style (CPS): you pass a
> function closure (continuation) containing everything that's needed
> in subsequent computations.  Instead of returning a result, the
> sub-function calls the continuation with the result, which makes the
> functions tail-recursive.

zipper 是一种处理巨大(实际是无限)tree 的简单方法。
Zippers are a simple way to handle huge (in fact infinite) trees.

Translation. Guile's reader, in guile [jsr-000R]

tips: Click on the translation to expand and view the original text. 点击译文可展开查看原文。

晚上好!今天的简短(大概?)记录是一些关于 guile 书呆子 ( nargery ) 的内容。
Good evening! A brief note today about some Guile nargery.

Translation. Baby’s First Garbage Collector [jsr-000P]

tips: Click on the translation to expand and view the original text. 点击译文可展开查看原文。

当我感到压力大、要做的事情太多时,我会产生一种矛盾的反应:通过找其他事情来逃避。通常这件事是一个我可以编写和完成的小型独立程序。
When I get stressed out and have too much to do, I have this paradoxical reaction where I escape from that by coming up with another thing to do. Usually it’s a tiny self-contained program that I can write and finish.

一天早上,我正对我正在写的书我在工作中必须做的事情以及我正在为《Strange Loop》准备的演讲感到害怕,突然间,我想,“我应该写一个垃圾回收器。”
The other morning, I was freaking myself out about the book I’m working on (http://gameprogrammingpatterns.com/) and the stuff I have to do at work (http://dart.dev/) and a talk I’m preparing for Strange Loop (https://www.infoq.com/presentations/dart-introduction/), and all of the sudden, I thought, “I should write a garbage collector.”

是的,我意识到那段话让我看起来有多么疯狂。但我的搭错神经带来的是编程语言实现基础的免费教程!在大约一百行常规 C 代码中,我成功地创建了一个基础的标记清除,你知道的,垃圾回收。
Yes, I realize how crazy that paragraph makes me seem. But my faulty wiring is your free tutorial on a fundamental piece of programming language implementation! In about a hundred lines of vanilla C, I managed to whip up a basic mark-and-sweep (https://en.wikipedia.org/wiki/Tracing_garbage_collection#Na%C3%AFve_mark-and-sweep) collector that actually, you know, collects.

一般认为,垃圾回收是编程中充满挑战的领域之一,不过在这篇文章里,我会引导你走上一条相对平坦的道路。(路上仍然可能有坑,但至少会浅一点)
Garbage collection is considered one of the more shark-infested waters of programming, but in this post, I’ll give you a nice kiddie pool to paddle around in. (There may still be sharks in it, but at least it will be shallower.)

Translation. Zipper in scheme [jsr-000O]

Title added by translator. 标题由译者添加。
tips: Click on the translation to expand and view the original text. 点击译文可展开查看原文。