为什么没有面向程序员的《数学漫游指南》( 篇 2)

注:本文为 “程序员数学( 篇 1)” 原文讨论中提及的文章的译文。
英文引文,机翻未校。
如有内容异常,请看原文。


Mathematicians are chronically lost and confused (and that’s how it’s supposed to be)

数学家总是迷茫又困惑(而这本该如此)

2014-03-03

A large part of my audience over at Math ∩ Programming are industry software engineers who are discovering two things about mathematics: it’s really hard and it opens the door to a world of new ideas. In that way it’s a lot like learning to read. Once you’re mildly fluent you can read books, use the ideas to solve problems, and maybe even write an original piece of your own.
我在数学与编程平台的读者中,很大一部分是行业软件工程师,他们在接触数学的过程中发现了两件事:数学难度极高,且能为他们打开一个充满新思想的世界。从这个角度来说,学习数学与学习阅读十分相似。一旦你达到一定熟练度,便能阅读相关书籍、运用所学思想解决问题,甚至可能创作出属于自己的原创内容。

Many people who are in this position, trying to learn mathematics on their own, have roughly two approaches. The first is to learn only the things that you need for the applications you’re interested in. There’s nothing wrong with it, but it’s akin to learning just enough vocabulary to fill out your tax forms. It’s often too specialized to give you a good understanding of how to apply the key ideas elsewhere. A common example is learning very specific linear algebra facts in order to understand a particular machine learning algorithm. It’s a commendable effort and undoubtedly useful, but in my experience this route makes you start from scratch in every new application.
许多处于这种自主学习数学状态的人,大致采用两种方法。第一种是仅学习自己感兴趣的应用场景所需的内容。这种方法本身并无不妥,但就好比仅学习填写纳税申报表所需的词汇一样——专业性过强,难以让你掌握将关键思想应用于其他领域的能力。一个常见的例子是:为了理解某一特定机器学习算法,而学习线性代数中非常具体的知识点。这种努力值得肯定,也无疑具有实用性,但根据我的经验,这种学习路径会让你在每一个新的应用场景中都需从零开始。

The second approach is to try to understand everything so thoroughly as to become a part of it. In technical terms, they try to grok mathematics. For example, I often hear of people going through some foundational (and truly good) mathematics textbook forcing themselves to solve every exercise and prove every claim “left for the reader” before moving on.
第二种方法是试图极为透彻地理解所有内容,直至将其内化。从专业角度来说,他们试图“深度领悟”数学。例如,我常听说有人在研读某些基础性(且确实优质)的数学教材时,会强迫自己解决每一道习题,并证明每一个“留给读者”的结论后,才继续往下学习。

This is again commendable, but it often results in insurmountable frustrations and quitting before the best part of the subject. And for all one’s desire to grok mathematics, mathematicians don’t work like this! The truth is that mathematicians are chronically lost and confused. It’s our natural state of being, and I mean that in a good way.
这种做法同样值得称赞,但往往会导致难以克服的挫败感,让人在接触到学科最精彩的部分之前就选择放弃。而且,无论一个人多么渴望深度领悟数学,数学家们并非如此工作! 事实是,数学家们总是处于迷茫和困惑之中。这是我们的自然状态,且我认为这是一种积极的状态。

Andrew Wiles, one of the world’s most renowned mathematicians, wonderfully describes research like exploring a big mansion.
安德鲁·怀尔斯(Andrew Wiles)是世界上最著名的数学家之一,他将研究巧妙地比作探索一座巨大的宅邸。

You enter the first room of the mansion and it’s completely dark. You stumble around bumping into the furniture but gradually you learn where each piece of furniture is. Finally, after six months or so, you find the light switch, you turn it on, and suddenly it’s all illuminated. You can see exactly where you were. Then you move into the next room and spend another six months in the dark. So each of these breakthroughs, while sometimes they’re momentary, sometimes over a period of a day or two, they are the culmination of, and couldn’t exist without, the many months of stumbling around in the dark that precede them.
你走进宅邸的第一个房间,里面一片漆黑。你跌跌撞撞地摸索,不断撞到家具,但渐渐地,你开始熟悉每一件家具的位置。终于,大约六个月后,你找到了电灯开关,按下它,房间瞬间被照亮。你能清晰地看到自己之前所处的位置。然后你走进下一个房间,又在黑暗中度过六个月。因此,每一次突破——无论有时是瞬间的,有时是持续一两天的——都是此前数月在黑暗中摸索的结晶,没有这些摸索,突破便无从谈起。

Wiles discusses what it’s like to do mathematical research here, but I’d argue that the same analogy largely holds for learning mathematics.
怀尔斯在这里描述的是进行数学研究的感受,但我认为这个比喻同样适用于数学学习。

If you’re going to get anywhere in learning mathematics, you need to learn to be comfortable not understanding something. Speaking with experienced mathematicians, and reading books written by them, almost always feels like the following sketch about math class as imagined by kids.
如果想在数学学习中取得进展,你需要学会坦然接受自己对某些内容的不理解。与资深数学家交流,或阅读他们撰写的书籍,几乎总会让人产生一种感受,就像下面这幅孩子们想象中的数学课速写所描绘的那样。

kidmath.png

Aside from being absolutely hilarious, the video has a really deep and probably unintentional truth, that the more mathematics you try to learn the more you feel like the poor student! The video especially resonates when, toward the end, the teacher asks, “Do you get it now?” and the student pauses and slowly says, “Yes.” That ‘yes’ is the fledgling mathematician saying, “I obviously don’t understand, but I’ve accepted it and will return to it later (maybe).”
这段视频除了极具幽默感外,还蕴含着一个深刻且可能是无意为之的真理:你越试图学习更多数学知识,就越会觉得自己像那个可怜的学生!视频结尾处的场景尤其能引起共鸣:老师问“现在懂了吗?”,学生停顿了一下,缓缓地说“懂了”。这个“懂了”,其实是初涉数学的学习者在表达:“我显然没懂,但我已经接受了这一点,之后(或许)会再回来研究它。”

I’ve been in the students’ shoes a thousand times. Indeed, if I’m not in his shoes at least once a day then it wasn’t a productive day! I say at least a dozen stupid things daily and think countlessly many more stupid thoughts in search of insight. It’s a rare moment when I think, “I’m going to solve this problem I don’t already know how to solve,” and there is no subsequent crisis.
我曾无数次处于那个学生的境地。事实上,如果我一天中没有至少一次陷入这种状态,那这一天就算不上有收获!我每天至少会说十几句蠢话,在追寻洞见的过程中,还会产生无数更愚蠢的想法。很少有这样的情况:当我心想“我要解决这个我还不知道如何下手的问题”时,后续不会遇到困境。

But I’m comfortable in my discomfort. This is something that has been bred into me after years of studying mathematics. I know how to say, “Well, I understand nothing about anything,” and then constructively answer the question, “What’s next?” Sometimes the answer is to pinpoint one very basic question I don’t understand and try to tackle that first. Other times it’s to learn what I can and move on.
但我能坦然面对这种不适感。这是我多年学习数学后逐渐养成的能力。我知道如何在说出“好吧,我对所有事情都一无所知”之后,建设性地回答“接下来该做什么?”这个问题。有时答案是找出一个我不理解的最基础问题,先尝试解决它;有时则是尽我所能学习当下能掌握的内容,然后继续前进。

I had a conversation with an immensely talented colleague, a PhD candidate at UM Ann Arbor and a far more talented mathematician than I, in which she said (I paraphrase),
我曾与一位极具才华的同事交流过,她是密歇根大学安娜堡分校(UM Ann Arbor)的博士生,也是一位比我优秀得多的数学家。她的大致意思是:

If I spend an entire day and all I do is understand this one feature of this one object that I didn’t understand before, then that’s a great day.
如果我花了一整天时间,最终只理解了某个对象的一个此前不了解的特性,那这就是很棒的一天。

We all have to build up our insights over time, and it’s an often slow and arduous process. In Andrew Wiles’s analogy, my friend is still in the dark room, but she’s feeling some object precisely enough to understand that it’s a vase. She still has no idea where the light switch is, and the vase might give her no indication as to where to look next. But if piece by piece she can construct a clear enough picture of the room in her mind, then she will find the switch. What keeps her going is that she knows enough little insights will lead her to a breakthrough worth having.
我们都需要通过时间积累洞见,这通常是一个缓慢而艰辛的过程。用安德鲁·怀尔斯的比喻来说,我的这位朋友仍处于黑暗的房间里,但她通过精准触摸某个物体,意识到那是一个花瓶。她仍然不知道电灯开关在哪里,而这个花瓶可能也无法为她指明下一步该往何处寻找。但如果她能一点一点地在脑海中构建出房间的清晰图景,就一定能找到开关。支撑她坚持下去的,是她知道足够多的微小洞见终将引领她取得值得的突破。

And it’s not even like one needs to understand every piece of a mathematical argument to have some useful insight about it. Sometimes I will just accept some detail of an argument and focus on the bigger picture, and other times the big picture will be completely mysterious and I will focus on the details. The math isn’t going anywhere. I can always come back to it, and it can often happen that one particular detail doesn’t hinder my insights (as you do more mathematics, insights come on a bigger and bigger-picture scale).
而且,要获得关于某个数学论证的一些有用洞见,并不需要理解其每一个细节。有时我会接受论证中的某些细节,转而关注整体框架;有时整体框架完全令人困惑,我就会专注于细节。数学知识不会消失,我总能回过头来重新研究它。而且常常会出现这样的情况:某个特定细节并不会阻碍我获得洞见(随着你接触更多数学知识,洞见会越来越偏向宏观层面)。

So, dear reader aspiring to grok linear algebra or calculus or any mathematical subject, I suggest you don’t worry too much about verifying every claim and doing every exercise. If it takes you more than 5 or 10 minutes to verify a “trivial” claim in the text, then you can accept it and move on. Thinking about other problems in the mean time is a healthy way to clear your mind, and even better is working with a friend. Sure, sometimes you can’t get away without working out every detail. Sometimes you just have to bang your head against a wall for an hour to get through the really important theorems. But more often than not you’ll find that by the time you revisit a problem you’ve literally grown so much (mathematically) that it’s trivial.
因此,亲爱的读者,如果你渴望深度领悟线性代数、微积分或任何数学学科,我建议你不必过分纠结于验证每一个结论或完成每一道习题。如果验证文本中一个“显而易见”的结论需要花费你超过 5 分钟或 10 分钟,那么你可以先接受它,然后继续往下学习。在此期间思考其他问题是理清思路的有效方式,与朋友合作学习则更佳。当然,有时你无法回避对每一个细节的钻研——有时你必须花费一小时“苦思冥想”,才能掌握那些真正重要的定理。但更多时候,当你再次回顾某个问题时,会发现自己在数学层面已经取得了长足进步,这个问题如今已变得微不足道。

What’s much more useful is recording what the deep insights are, and storing them for recollection later. Because every important mathematical idea has a deep insight, and these insights are your best friends. They’re your mathematical “nose,” and they’ll help guide you through the mansion.
更有用的做法是记录下那些深刻的洞见,并储存起来以备日后回忆。因为每一个重要的数学思想都蕴含着深刻的洞见,这些洞见是你最好的朋友。它们就像你的数学“嗅觉”,会帮助你在这座“宅邸”中找到前进的方向。


Programming is not math, huh?

编程不是数学,对吧?

July 18, 2014

You’re right, programming isn’t math. But when someone says this, chances are it’s a programmer misunderstanding mathematics.
你说得对,编程不是数学。但当有人说出这句话时,大概率是程序员对数学产生了误解。

I often hear the refrain that programmers don’t need to know any math to be proficient and have perfectly respectable careers. And generally I agree. I happen to think that programming only becomes fun when you incorporate mathematical ideas, and I happen to write a blog about the many ways to do that, but that doesn’t stop me from realizing that the vast majority of programmers completely ignore mathematics because they don’t absolutely need it.
我常听到这样的说法:程序员无需掌握任何数学知识,也能熟练工作并拥有体面的职业。总体而言,我认同这一观点。我个人认为,只有融入数学思想,编程才会变得有趣——我也确实撰写了一个博客,探讨实现这一目标的多种方式——但这并不妨碍我意识到,绝大多数程序员完全忽视数学,因为他们并非绝对需要它。

So when Sarah Mei argues in her article “Programming is not Math” that math skills should not be considered the only indicator of a would-be programmer’s potential, I wholeheartedly agree. I’ve never heard anyone make that argument, but I’m much younger than she is. Having faith in Mei’s vast life experience, I’ll assume it was this way everywhere when she was writing Fortran in school, and it seems plausible that the attitude lingers at the most prestigious universities today.
因此,当萨拉·梅(Sarah Mei)在其文章《编程不是数学》中主张,不应将数学能力视为准程序员潜力的唯一衡量标准时,我完全同意。我从未听过有人提出这样的论点,但我比她年轻得多。基于对梅丰富人生阅历的信任,我推测她上学时编写 Fortran 语言的年代,这种观念可能普遍存在;而且在如今最顶尖的大学里,这种态度似乎也有可能依然存在。

But then she goes on to write about mathematics. As much as I respect her experience and viewpoints, her article misses the title’s claim by a long shot. It’s clear to me that it’s because she doesn’t understand the mathematics part of her argument. Here’s the best bit:
但随后她开始谈及数学。尽管我尊重她的经验和观点,但她的文章与标题所主张的内容相去甚远。在我看来,这显然是因为她未能理解自己论点中涉及数学的部分。以下是最能体现这一点的段落:

Specifically, learning to program is more like learning a new language than it is like doing math problems. And the experience of programming today, in industry, is more about language than it is about math.
具体来说,学习编程更像是学习一门新语言,而非解答数学题。如今在行业中,编程的实际体验更多与语言相关,而非数学。

This is the core of her misunderstanding: being good at math is not about being good at “doing math problems” (from the context of her article it’s clear that she equates this with computation, e.g. computing Riemann sums). And the experience of programming in your particular corner of industry is not representative of what programming is about. The reality of the mathematics/programming relationship is more like this:
这正是她误解的核心:擅长数学并非指擅长“解答数学题”(从文章上下文可以明确,她将此等同于计算,例如计算黎曼和)。而且,你所在行业细分领域的编程体验,并不能代表编程的本质。数学与编程之间的真实关系更接近以下几点:

  1. Mathematics is primarily about conjecture, proof, and building theories, not doing slews of computations.
    数学的核心在于猜想、证明和构建理论,而非进行大量计算。

  2. Learning to do mathematics is much more like learning language than learning to program is like learning language.
    学习数学比学习编程更接近于学习语言。

  3. Large amounts of effort are spent on tedious tasks in industry for no reason other than that we haven’t figured out how to automate them yet. And novel automations of tedious tasks involve interesting mathematics by rule, not exception.
    行业中大量精力被用于繁琐的任务,原因仅仅是我们尚未找到自动化这些任务的方法。而对繁琐任务的创新性自动化,通常(而非例外)会涉及有趣的数学知识。

  4. That doesn’t change how crucially reliant every programmer (and every company) is on the mathematical applications to programming that allow them to do their work.
    这并不改变每个程序员(以及每家公司)对数学在编程中应用的极度依赖——正是这些应用使他们能够开展工作。

Mathematics is closer to language

数学更接近语言

Item 2 is probably why Mei isn’t able to find any research on the similarities between math and programming. There is a ton of research relating mathematics to language learning. For an extended bibliography with a nice narrative, see Keith Devlin’s book The Math Gene.
上述第二点或许正是梅未能找到任何关于数学与编程相似性研究的原因。而关于数学与语言学习之间的关联,已有大量研究。若想了解详细的文献综述及相关论述,可参阅基思·德夫林(Keith Devlin)的著作《数学基因》(The Math Gene)。

One big reason that mathematics is much more like language than programming, is that doing mathematics involves resolving ambiguities. In programming you have a compiler/interpreter that just dictates how an ambiguity resolves. But in mathematics, as in real language, you have to resolve them yourself based on context. This happens both in the modeling side of mathematics and in the hard-core theory side. Contrary to the most common internet wisdom, almost no working mathematicians do math from a purely axiomatic standpoint. The potential for ambiguities arises in trying to communicate a proof from one person to another in an elegant and easy-to-understand way. Note the focus on communicating. This is essentially the content of a first course in proofs, which, by the way, is usually titled something like “A transition to advanced mathematics.” The reason that this never shows up when you’re computing Riemann sums is because in that context you’re playing the role of the computer and not the mathematician. It’s like getting the part of a spear carrier in a play and claiming, “acting is just about standing around looking fierce!” It’s a small, albeit important, part of a much larger picture.
数学比编程更接近语言的一个重要原因是,做数学需要解决歧义。在编程中,编译器/解释器会直接规定歧义的解决方式;但在数学中,如同在真实语言中一样,你必须根据上下文自行解决歧义。这一现象既存在于数学的建模层面,也存在于核心理论层面。与互联网上最普遍的观点相反,几乎没有在职数学家是从纯公理的角度进行数学研究的。当试图以简洁易懂的方式向他人传达一个证明时,歧义就可能产生——请注意这里对“沟通”的强调。这本质上正是一门基础证明课程的核心内容(顺便说一句,这类课程的标题通常类似于《高等数学入门》)。而当你计算黎曼和时,从未遇到过这种情况,因为在这种场景下,你扮演的是计算机的角色,而非数学家。这就好比在戏剧中扮演一个持矛士兵,然后声称“演戏不过是站在那里装凶罢了!”——这只是一个宏大体系中虽重要但微小的部分。

Having studied all three subjects, I’d argue that mathematics falls between language and programming on the hierarchy of rigor.
通过对这三个领域的学习,我认为在严谨性的层级上,数学介于语言和编程之间:

  • Human language
    人类语言

  • Mathematics
    数学

  • Programming
    编程

and the hierarchy of abstraction is the exact reverse, with programming being the most concrete and language being the most abstract. Perhaps this is why people consider mathematics a bridge between human language and programming. Because it allows you to express more formal ideas in a more concrete language, without making you worry about such specific hardware details like whether your integers are capped at 32 bits or 64. Indeed, if you think that the core of programming is expressing abstract ideas in a concrete language, then this makes a lot of sense.
而抽象性的层级则完全相反:编程最为具体,语言最为抽象。或许这就是人们将数学视为人类语言与编程之间桥梁的原因——它允许你用更具体的语言表达更形式化的思想,而无需担心诸如整数是 32 位还是 64 位上限等具体硬件细节。事实上,如果你认为编程的核心是用具体语言表达抽象思想,那么这一观点就非常合理。

This is precisely why learning mathematics is “better” at helping you learn the kind of abstract thinking you want for programming than language. Because mathematics is closer to programming on the hierarchy. It helps even more that mathematics and programming readily share topics. You teach graph coloring for register allocation, linear algebra and vector calculus for graphics, combinatorics for algorithms. It’s not because you need to know graph coloring or how to count subsets of permutations, but because it shows the process of reasoning about an idea so you can understand the best way to organize your code. If you want to connect language to programming you almost always have to do so through mathematics (direct modeling of sentence structure via programming is a well-tried and unwieldy method for most linguistic applications).
这也正是为什么学习数学在帮助你培养编程所需的抽象思维方面,比学习语言“更有效”——因为在层级关系上,数学更接近编程。此外,数学与编程还存在诸多共通主题,这进一步增强了其辅助作用:例如,寄存器分配需要学习图着色,图形学需要线性代数和向量微积分,算法设计需要组合数学。这并非因为你需要掌握图着色或排列子集的计数方法,而是因为这些内容展示了对一个思想进行推理的过程,帮助你理解组织代码的最佳方式。如果你想将语言与编程联系起来,几乎总是需要通过数学作为中介(对于大多数语言学应用而言,通过编程直接建模句子结构是一种尝试已久但繁琐不便的方法)。

Big-O is “pretty much meaningless”

大 O 记法“几乎毫无意义”

Another issue I have with Mei’s article is on her claim that “big-O” is meaningless in the real world. More specifically, she says it only matters what the runtime of an algorithm is on “your data.”
我对梅的文章还有一个异议,在于她声称“大 O 记法”在现实世界中毫无意义。更具体地说,她认为算法的运行时间仅取决于“你的数据”。

Let’s get the obvious thing out of the way. I can name many ways in which a result in improving the worst-case asymptotic complexity of an algorithm has literally changed the world. Perhaps the biggest is the fast Fourier transform. So if you’re applying to work at a company like Google, which deservingly gets credit for changing the world, it makes total sense for interviewees to be familiar with the kind of mathematical content that has changed the world in the past. Maybe it’s a mistake for smaller companies to emulate Google, but you can’t blame them for wanting to hire people who would do well at Google.
首先,我们先澄清一个显而易见的事实:改进算法的最坏情况渐近复杂度所带来的成果,在很多方面确实改变了世界。其中最典型的例子或许是快速傅里叶变换(FFT)。因此,如果你申请加入谷歌(Google)这样一家当之无愧的“改变世界”的公司,面试官希望应聘者熟悉这类曾改变世界的数学内容,是完全合理的。或许小公司效仿谷歌的做法并不恰当,但你不能责怪他们希望招聘到在谷歌也能表现出色的人才。

But at a deeper level I don’t believe Mei’s argument. Her example is this.
但在更深层次上,我并不认同梅的观点。她给出的例子如下:

An algorithm that is O(n²) for arbitrary data may actually be constant time (meaning O(1)) on your particular data, and thus faster than an algorithm that is O(n log n) no matter what data you give it.
一个对任意数据的时间复杂度为 O(n²) 的算法,在你的特定数据上可能实际是常数时间(即 O(1)),因此比无论输入何种数据时间复杂度均为 O(n log n) 的算法更快。

First, the chance is absolutely negligible that you will come across a nontrivial problem where the runtime of a standard algorithm meets the worst case on “your” data, but when you use a generally-considered worse algorithm it does much better. Second, there is a very rich mathematical theory of, “algorithms that run extremely fast and return correct answers to queries with high probability.” So again, you can turn to mathematics where the expectations are quantifiable rather than arbitrary and guessed.
首先,在非平凡问题中,出现“标准算法在你的数据上达到最坏情况,而使用通常被认为更差的算法却表现优异”的概率极低。其次,关于“运行速度极快且以高概率返回正确查询结果的算法”,存在一套非常丰富的数学理论。因此,你再次可以求助于数学——在数学中,预期结果是可量化的,而非主观猜测的。

But more deeply, nobody in industry has any clue what it is that characterizes “real world data” that allows you to make worst-case guarantees. They have a fuzzy idea (real social networks are usually sparse, etc.), but little in the way of a comprehensive understanding. This is a huge topic, but it’s a topic of active research, which is uncoincidentally filled to the brim with mathematics. The takeaway is that even if you have an algorithm that seems to run quickly on “your” data, “seems” is the best you’ll be able to say without answering big open research questions. You won’t be able to guarantee anything, which means you’ll be stuck telling your manager that you’re introducing more points of failure into the system, and you risk being paged in the middle of the night because the company has expanded to China and their data happens to break your algorithm on average.
但更核心的问题是:行业中没有人确切知道“现实世界数据”具有哪些特征,能够支持我们做出最坏情况的保证。人们对此只有模糊的认知(例如,真实的社交网络通常是稀疏的),但缺乏全面的理解。这是一个庞大的研究领域——而且巧合的是,该领域充满了数学知识。关键在于,即使你的算法在“你的数据”上看似运行迅速,但在解决这些重大开放性研究问题之前,“看似”已是你能给出的最佳描述。你无法做出任何保证,这意味着你只能告知管理者,你正在为系统引入更多故障点;而且当公司业务扩展到中国,当地数据恰好平均而言会导致你的算法失效时,你可能会在半夜被紧急呼叫处理问题。

But you’re a smart engineer, so what do you do? You run your clever algorithm and track how long it takes; if it takes too long, you abort and do the standard O(n log n) solution instead. Problem solved. But wait! You needed to know the difference between your algorithm’s worst case complexity and the baseline complexity, and you had to determine how long to wait before aborting.
但你是一名聪明的工程师,所以你会怎么做?你可以运行你设计的巧妙算法,并跟踪其运行时间;如果耗时过长,就中止该算法,转而使用标准的 O(n log n) 复杂度解决方案。问题似乎解决了。但等一下!你需要知道你的算法的最坏情况复杂度与基准复杂度之间的差异,并且必须确定中止前的等待时间。

The fact is, you can’t function without knowing the baselines, and asymptotic runtime (big-O) is the gold standard for comparing algorithms. Certainly you can mix things up as appropriate, as the fictional engineer in our story did, but if you’re going to do a more detailed analysis you have to have a reference frame. At a company where a one-in-a-million error happens a hundred times a day, mathematical guarantees are (literally) what help you sleep at night. Not every programmer deals with these questions regularly (which is why I don’t think math is necessary to be a programmer), but if you want to be a great programmer you had better bet you’ll need it. Companies like Google and Amazon and Microsoft face these problems, aspire to greatness, and want to hire great programmers. And great programmers can discuss the balance issues of various algorithms.
事实是,没有基准作为参考,你就无法开展工作;而渐近运行时间(大 O 记法)是比较算法的黄金标准。当然,你可以像我们故事中虚构的工程师那样,根据情况灵活组合使用不同算法,但如果要进行更详细的分析,你必须有一个参考框架。在一家“百万分之一的错误每天发生一百次”的公司里,数学保证(确实)是让你能够安心入睡的关键。并非每个程序员都会定期处理这些问题(这也是我认为数学并非成为程序员的必备条件的原因),但如果你想成为一名优秀的程序员,那么你很可能需要掌握这些知识。谷歌、亚马逊、微软等公司面临着这些问题,它们追求卓越,并希望招聘到优秀的程序员——而优秀的程序员能够讨论各种算法的权衡问题。

But Sarah Mei is right, there might be some interesting ways to model algorithms running better on “your” data than the worst case (and if I were interviewing someone I would gladly entertain such a discussion), but I can say with relative certainty that even an above-average math-phobic interviewee is not going to have any new and deep insights there. And even if one does, one needs to be able to answer the question of how this relates to what is already known about the problem. Without that how can you know your solution is better?
但萨拉·梅的观点也有一定道理:确实存在一些有趣的方法,可以对“在你的数据上运行效果优于最坏情况”的算法进行建模(如果我在面试中遇到有人探讨这一话题,我会很乐意参与讨论)。但我可以相对肯定地说,即使是数学基础高于平均水平的“恐数”应聘者,也不太可能在这一领域有新的深刻见解。而且,即使有人有这样的见解,也需要能够回答“这与该问题的现有已知成果有何关联”这一问题——否则,你如何确定你的解决方案更优?

A “minor specialization”

一项“次要专长”

Now my biggest beef is with her conclusive dismissal of mathematics.
现在,我最大的异议在于她对数学的断然否定:

If a small and shrinking set of programming applications require math, so much so that we cordon you off into your own language to do it, then it’s pretty clear that heavy math is, these days, a minor specialization.
倘若仅有少数且日益减少的编程应用场景需要数学,以至于我们需要为这类工作单独划分出专属编程语言,那么显然,如今高深数学不过是一项次要专长。

Oh please. You can’t possibly think that every mathematician who programs does so in Fortran or Haskell. I’m a counterexample: I’m proficient in C, C++, Java, Python, Javascript, HTML and CSS. I have only really dabbled in Haskell and Racket and other functional languages (I like them a lot, but I just get more done in Python).
拜托。你不可能认为所有编程的数学家都在用 Fortran 或 Haskell 吧?我就是一个反例:我熟练掌握 C、C++、Java、Python、Javascript、HTML 和 CSS,仅对 Haskell、Racket 等函数式语言略有涉猎(我很喜欢这些语言,但用 Python 能完成更多工作)。

But what’s worse is that I have so many programming applications of mathematics that I don’t know what to do with them all. It’s like they’re sprouting from my ears!
但更重要的是,我能想到的数学在编程中的应用场景多得数不胜数,就像源源不断地从脑海中冒出来一样!

Let’s take the examples of what Mei thinks are purely unmathematical uses of programming: “ease of use, connectivity, and interface.” I’m assuming she means the human-computer interaction version of these questions. So this is like, how to organize a website to make it easy for users to find information and streamline their workflow. I’d question whether anyone in the industry can really be said to be “solving” these problems rather than just continually debating which solution they arbitrarily think is best. In fact, I’m more inclined to argue that companies change their interface to entice users to pay for updates more than to make things easier to use (I’m looking at you, Microsoft Word).
让我们看看梅认为完全与数学无关的编程应用场景:“易用性、连通性和界面设计”。我推测她指的是这些问题在人机交互领域的应用——例如,如何设计网站结构,让用户更容易找到信息并简化操作流程。但我不禁质疑,行业中是否有人真正在“解决”这些问题,而不是不断争论哪种方案是他们主观认为的最佳选择。事实上,我更倾向于认为,公司更改界面更多是为了吸引用户付费升级,而非提升易用性(说的就是你,微软 Word)。

In any case, it’s clear that Mei is biased toward one very specific kind of programming, which does have mathematical aspects (see below). But moreover, she blurs the distinction between an application of mathematics to programming and what she finds herself and her colleagues actively doing in her work. Let me counter with my own, more quantifiable examples of the mind-bogglingly widespread applications of mathematics to industry, both passive and active.
无论如何,梅显然偏向于某一种特定类型的编程——而这种编程本身其实也包含数学元素(见下文)。此外,她混淆了“数学在编程中的应用”与“她和同事在工作中实际从事的事务”这两个概念。下面我将列举一些更具量化性的例子,展示数学在工业界中广泛到令人惊叹的应用——既有被动应用,也有主动应用。

Optimization: the big Kahuna of mathematical applications to the real world. Literally every industrial company relies on state-of-the-art optimization techniques to optimize their factories, shipping lines, material usage, product design. And I’m not even talking about the software industry here. I’m talking about Chevron, Walmart, Goldman Sachs. Every single Fortune 500 company applies more “heavy” math on a daily basis than could be taught in four years of undergraduate education. They don’t care about ease of use, they care about getting that extra 0.05% profit margin. And as every mathematician knows, there is a huge theory of optimization that ranges from linear programming to functional analysis to weird biology-inspired metaheuristics.
优化理论:这是数学在现实世界中最核心的应用领域。几乎所有工业企业都依赖最先进的优化技术,对工厂运营、运输线路、材料使用、产品设计等进行优化——我这里甚至还没提到软件行业。我说的是雪佛龙(Chevron)、沃尔玛(Walmart)、高盛(Goldman Sachs)这类企业。每一家《财富》500 强公司每天应用的“高深”数学,其总量都超过了四年本科教育所能教授的内容。它们不关心易用性,只关心能否多获得 0.05% 的利润率。而正如每位数学家所知,优化理论体系极为庞大,涵盖线性规划、泛函分析,以及受生物学启发的各类奇异元启发式算法。

Signal processing: No electric device or wireless communication system would exist without signal processing. The entire computer industry relies on digital signal processing techniques and algorithms proliferated via mathematics. Literally every time you type a key on your keyboard, you’re relying on applications of mathematics to programming. Sure, you don’t need to know how to build a car to drive it, but signal processing techniques extend to other areas of programming, such as graphics, data mining, and optimization, and a large portion of the software industry is disguised as the hardware industry because they use languages like VHDL instead of Ruby. They really need to know this topic, and it’s not fair to forget them. That being said, let’s not forget all the engineers who do signal processing in Matlab. Our list just keeps getting bigger and bigger, huh?
信号处理:没有信号处理,就没有任何电子设备或无线通信系统。整个计算机行业都依赖于通过数学推导得出的数字信号处理技术和算法。事实上,每次你敲击键盘,都在依赖数学在编程中的应用。当然,你不必知道如何造车就能开车,但信号处理技术已延伸到编程的其他领域(如图形学、数据挖掘、优化理论);而且软件行业中有很大一部分实际上“伪装”成了硬件行业——因为他们使用的是 VHDL 而非 Ruby 这类语言。这些从业者确实需要掌握这一领域的知识,忽略他们是不公平的。此外,也不要忘记所有在 Matlab 中进行信号处理的工程师——我们的例子是不是越来越多了?

Statistics: Every company needs to manage their risk and finances via statistics, and every application of mathematics and statistics to risk and finance is done via programming. Whether you use SAS, JMP, R, or just Excel, it’s all programming and all requires mathematical understanding. This is not even to mention all of the statistical modeling (via programming) that goes on in a non-financial setting. For example, in Obama’s presidential campaign and in sports forecasting. Even as I write this, NPR is reporting on the Malaysia flight that was shot down in Ukraine, and how technicians are using “mathematics and algorithms” to pinpoint the location of the crash.
统计学:每家公司都需要通过统计学管理风险和财务,而所有将数学与统计学应用于风险和财务领域的工作,都是通过编程实现的。无论你使用 SAS、JMP、R 还是仅仅使用 Excel,本质上都是编程,且都需要数学知识作为支撑。更不用说非金融领域中通过编程进行的各类统计建模——例如,奥巴马总统竞选期间的数据分析、体育赛事预测等。就在我撰写本文时,美国国家公共广播电台(NPR)正在报道乌克兰击落马来西亚航班的事件,以及技术人员如何利用“数学和算法”确定坠机地点。

Machine Learning: A hot topic these days, but for a long time engineers have been trying to answer the question, “what does it mean for a computer to learn?” Surprise, surprise, the generally accepted answer these days came from mathematicians. The theory of PAC-learning, and more generally its relationship to the many widely-used machine learning techniques, paved the way for things like boosting and the study of statistical query algorithms. Figuring out smart ad serving? Try bandit-learning techniques. It’s mathematics all the way down.
机器学习:这是如今的热门话题,但长期以来,工程师们一直在试图回答“计算机学习意味着什么?”这一问题。说来也怪,如今被广泛接受的答案恰恰来自数学家。概率近似正确学习(PAC-learning)理论,以及该理论与众多广泛应用的机器学习技术之间的关联,为提升算法(boosting)、统计查询算法等领域的研究奠定了基础。想实现智能广告投放?可以尝试多臂老虎机学习(bandit-learning)技术——这一切的核心都是数学。

Graphics/Layout: You want ease of use in human-computer interaction? You want graphics. You want special effects in movies? You need linear algebra, dynamical systems, lots of calculus, and lots of graphics programming. You want video games? Data structures, computational geometry, and twice as much graphics as you thought you’d ever need. You want a dynamic, adaptive, tile-based layout on your website? Get ready for packing heuristics, because that stuff is NP-hard! Information trees, word clouds, rankings, all of these layout concepts have rich mathematical underpinnings.
图形学/布局设计:你想要人机交互的易用性?就离不开图形学。你想要电影中的特效?就需要线性代数、动力系统、大量微积分知识,以及丰富的图形编程经验。你想要视频游戏?就需要数据结构、计算几何,以及比你想象中多一倍的图形学知识。你想要网站实现动态、自适应的瓦片式布局?那就得准备好学习装箱启发式算法——因为这类问题是 NP 难的!信息树、词云、排名系统,所有这些布局概念都有着深厚的数学基础。

You see, Mei’s fundamental misconception is that the kind of applications that we haven’t yet automated and modularized constitutes what programming is all about. We don’t know how to automate the translation of obscure and ambiguous business rules to code. We don’t know how to automate the translation from a picture you drew of what you want your website to look like to industry-strength CSS. We don’t know how to automate the organization of our code so as to allow us to easily add new features while maintaining backwards compatibility. So of course most of what goes on in the programming industry is on that side of the fence. And before we had compilers we spent all our time tracking memory locations and allocating registers by hand, too, but that’s no more the heart and soul of programming than implementing business rules.
你看,梅的根本误解在于,她认为编程的全部意义就在于那些我们尚未实现自动化和模块化的应用场景。我们不知道如何将晦涩模糊的业务规则自动转化为代码;不知道如何将你手绘的网站构想自动转化为工业级的 CSS;不知道如何自动组织代码,以便在保持向后兼容性的同时轻松添加新功能。因此,编程行业的大部分工作自然集中在这些领域。但就像在编译器出现之前,我们也曾花费大量时间手动跟踪内存地址和分配寄存器一样,这些工作与实现业务规则一样,都并非编程的核心本质。

And by analogy, most of writing is not literature but fact reporting and budget paperback romance novels, but we teach students via Twain and Wilde. And most cooking is reheating frozen food, not farm-to-table fine cuisine, so should a culinary student study McDonald’s?
打个比方:大多数写作并非文学创作,而是事实报道和廉价平装浪漫小说,但我们仍通过马克·吐温(Twain)和奥斯卡·王尔德(Wilde)的作品教授学生;大多数烹饪并非农场到餐桌的精致料理,而是加热冷冻食品,那么烹饪专业的学生应该学习麦当劳的做法吗?

But if you wanted to genuinely improve on any of these things, if you wanted to figure out how to automate the translation of drawn sketches to good HTML and CSS, you can count on there being some real mathematical meat for you to tenderize. I hope you try, because without mathematics we programmers are going to have an extremely hard time making real progress in our field.
但如果你想真正改进这些领域的任何一项技术——例如,想找出如何将手绘草图自动转化为优质 HTML 和 CSS 的方法——你肯定会遇到大量需要深入钻研的数学内容。我希望你能勇于尝试,因为没有数学,我们程序员将很难在自己的领域取得真正的进步。


Why don’t mathematicians write great code?

为什么数学家写不出优秀的代码?

August 25, 2014

In the discussion surrounding a series of recent articles on the question of how mathematics relates to programming (one of my favorite navel-gazing topics), the following question was raised multiple times:
在围绕近期一系列探讨数学与编程关系的文章所展开的讨论中(这是我最感兴趣的“自我审视”类话题之一),以下问题被多次提及:

If mathematics is so closely related to programming, why don’t professional (research) mathematicians produce great code?
既然数学与编程的联系如此紧密,为什么专业(研究型)数学家写不出优秀的代码?

The answer is quite a simple one: they have no incentive to.
答案十分简单:他们缺乏这样做的动力。

It’s pretty ridiculous to claim that a mathematician, someone who typically lives and breathes abstractions, could not learn to write well-organized and thoughtful programs. To give a simple example, I once showed my advisor a little bit about the HTML/CSS logical flow/style separation paradigm for webpages, and he found it extremely natural and elegant. And the next thing he said was along the lines of, “Of course, I would have no time to really learn and practice this stuff.” (And he says this as a relatively experienced programmer)
声称一名通常沉浸于抽象思维的数学家无法学会编写结构清晰、构思缜密的程序,这一说法相当荒谬。举一个简单的例子:我曾向我的导师简要介绍过网页的 HTML/CSS 逻辑流与样式分离范式,他认为这一设计极为自然且优雅。紧接着他说道:“当然,我根本没有时间去真正学习和实践这些东西。”(要知道,他本身已是一名相对有经验的程序员)

That’s the attitude of most researchers. Most programming tools are cool and would be good to have expertise in, but it’s not worth the investment. Mostly that comes off as, “this is a waste of time,” but what’s keeping them from writing great code is their career.
这正是大多数研究者的态度:大多数编程工具固然有趣,掌握相关技能也会带来便利,但为此投入时间并不值得。这种态度在很大程度上表现为“这是在浪费时间”,但真正阻碍他们写出优秀代码的,是其职业发展导向。

Mathematics and theoretical computer science researchers (and many other researchers) are rewarded for one thing: publications. There is no structure in place to reward building great software, and theoretical computer scientists in particular are very aware of this. There have even been some informal proposals to change that, because everyone understands how valuable good software libraries are to progress in our fields.
数学家和理论计算机科学家(以及许多其他领域的研究者)的职业回报仅与一件事相关:学术发表。目前并不存在奖励优秀软件开发的制度体系,而理论计算机科学家对此尤为清楚。尽管已有一些非正式的提议试图改变这一现状——因为所有人都明白,优质的软件库对相关领域的发展具有重要价值。

But as it currently stands, the incentives for mathematicians reward one thing and one thing only: publishing influential papers. There is very small emphasis given to things like teaching, software, or administrative duties. But the problem is that they don’t replace publications. So spending work time on things that are not publications takes away from time that could be spent on papers. Everyone understands this about the job market. Say you have two candidates of equally good work, but the first candidate has one more top-tier paper and the second has contributed an equal amount of work to open source software. Though I have never seen this happen first hand, every career panel I have posed this question to has agreed the first candidate would be chosen with high probability.
但就目前而言,数学家所面临的激励机制仅奖励一件事:发表具有影响力的论文。教学、软件开发或行政工作等事务仅受到极少关注,且这些事务无法替代学术发表的核心地位。因此,将工作时间投入到非发表相关的事务中,就意味着减少了可用于撰写论文的时间。就业市场的规则对此已有共识:假设有两位候选人的业务能力相当,第一位候选人多一篇顶级期刊论文,而第二位候选人在开源软件领域有同等价值的贡献。尽管我从未亲眼见过这种情况,但所有我咨询过的职业顾问小组都一致认为,第一位候选人被录用的概率极高。

So when mathematicians or theoretical computer scientists do write code, they have an incentive to get it working as quickly and cheaply as possible. They need the results for their paper and, as long as it’s correct, all filthy hacks are fair game. This is most clearly illustrated by the relationship between mathematicians and their primary paper-writing tool, the typesetting language TeX. All mathematicians are proficient with it, but almost no mathematicians actually learn TeX. Despite everyone knowing that TeX is a true programming language (it has a compiler and a Turing-complete macro system), everyone prefers to play guess-and-check with the compiler or find a workaround because it’s way faster than determining the root problem.
因此,当数学家或理论计算机科学家确实需要编写代码时,他们的动力是尽可能快速、低成本地实现功能。他们需要代码运行结果来支撑论文,而只要结果正确,所有不规范的权宜之计都是可接受的。这一点在数学家与他们的主要论文撰写工具——排版语言 TeX 的关系中体现得最为明显:所有数学家都能熟练使用 TeX,但几乎没有数学家会真正去“学习” TeX。尽管所有人都知道 TeX 是一门真正的编程语言(它具备编译器和图灵完备的宏系统),但大多数人更愿意通过编译器反复试错或寻找替代方案来解决问题——因为这比探究问题根源要快得多。

With this in mind, it’s hard to imagine your average mathematician having a deep enough understanding of a general-purpose language to produce code that software engineers would respect. So something like adequate testing, version control, or documentation is that much more unlikely. Even if they do write programs, most of it is exploratory, discarded once a proof is found achieving the same result. Modern software engineering practices just don’t apply.
考虑到这一点,我们很难想象普通数学家会对通用编程语言有足够深入的理解,从而编写出能获得软件工程师认可的代码。因此,诸如充分测试、版本控制或文档编写等软件工程实践,就更难在他们的代码中体现。即便他们确实编写了程序,这些程序大多也只是探索性的——一旦找到能得出相同结果的数学证明,代码就会被丢弃。现代软件工程实践在此完全不适用。

For the majority of mathematicians, I claim this is mostly as it should be. Building industry-strength tools is not the core purpose of academic research, and much of mathematical research is not immediately (or ever) applicable to software. And most large companies who want to utilize bleeding-edge research for practical purposes form research teams. For example, Google does this, and from what I’ve heard many of their researchers spend a lot of time working with engineers to test and deploy new research. At places like Google (and Yahoo, Microsoft, IBM, Toyota), researchers negotiate with their company how their time is split between academic-style paper writing and engineering pursuits, and there are researchers at both extremes.
我认为,对于大多数数学家而言,这种情况在很大程度上是合理的。构建工业级工具并非学术研究的核心目标,且许多数学研究无法立即(甚至永远无法)应用于软件领域。而大多数希望将前沿研究转化为实际应用的大公司,都会组建专门的研究团队。例如,谷歌(Google)就是如此——据我所知,他们的许多研究者会花费大量时间与工程师合作,测试并部署新的研究成果。在谷歌(以及雅虎、微软、IBM、丰田等公司),研究者会与公司协商时间分配方案,确定用于学术式论文撰写与工程实践的比例,而研究者在这两种工作上的投入程度也存在极大差异。

But even there, where coding is part of the goal, the best industry research teams still hire based on publication history. I can only hypothesize why: a great researcher can be taught programming practices trivially, so a strong research history is more important.
但即便在这些将编程纳入工作目标的机构中,顶尖的行业研究团队仍会根据学术发表经历来招聘人才。我只能对此做出推测:优秀的研究者能够轻松掌握编程实践,因此扎实的研究背景更为重要。

Kudos
致谢


I almost quit self-studying mathematics, but should I continue?

我几乎要放弃自学数学了,但我应该坚持下去吗?

Before I move on to the main idea of this post, I need to tell you some background information about myself. Hopefully, it proves useful for you in giving me advice. I’m a 16 year old high school student who just recently got interested in mathematics a couple of months ago. I was never interested in mathematics in elementary school and middle school. However, all of a sudden in the middle of my high school journey I got interested in it.
在进入本文的主要内容之前,我需要向大家介绍一些关于我自己的背景信息。希望这些信息能对大家给我提供建议有所帮助。我是一名 16 岁的高中生,几个月前才开始对数学产生兴趣。小学和初中阶段,我对数学从未有过兴趣。但在高中生涯进行到一半时,我突然对它产生了浓厚的兴趣。

Now back to the point.
现在言归正传。

Currently my mind is in a state of conflict! I do not know how I should self-study mathematics!
目前我的内心处于矛盾之中!我不知道该如何自学数学!

My original approach to self-studying math was to merely solve problems that caught my interest. For instance, I would search online (like this http://maaminutemath.blogspot.com/ ) or in a book for a problem that caught my attention. Then I would do my best to solve it. I would play with it like a toy. I would even try to create my own problems similar to the problems I solved. However, I realized this approach leads me to a lack of foundation. In other words, I have gaps in my knowledge!
我最初的数学自学方法只是解决那些吸引我的问题。例如,我会在网上(如 http://maaminutemath.blogspot.com/ )或书籍中寻找引起我注意的问题,然后尽最大努力去解决它。我会像玩玩具一样钻研这些问题,甚至会尝试仿照已解决的问题自己编题。但我意识到,这种方法导致我在知识体系上存在欠缺,换句话说,我的知识存在漏洞!

Because of this worry, I set myself a goal to focus on filling my gaps and building foundation. I bought an Art of Problem Solving book called Introduction to Algebra because of this. After awhile on working on the problems in the book, I got bored. The problems weren’t challenging or interesting. It was the usual find x x x and applied to some word problems. In fact, I already did algebra before in middle school, yet I felt like I should have continued to work on the problems no matter how dull to fill my gaps. UGH! It’s so frustrating.
出于这种担忧,我为自己设定了一个目标:专注于填补知识漏洞。为此,我购买了一本《解题艺术》系列的书籍——《代数导论》。但在做了书中的一些题目后,我感到很无聊。这些题目既没有挑战性,也缺乏趣味性,只是常见的求解 x x x 以及一些应用题。事实上,我在初中就已经学过代数了,但我觉得为了填补知识漏洞,无论这些题目多么枯燥,我都应该坚持做下去。唉!这太令人沮丧了。

Afterward, my mind diverted to something else. It was the Putnam problems like these: http://www.math.niu.edu/~rusin/problems-math/MP1975.html . I wanted to know how to solve them! They were very mysterious to me (and still are) because I do not know how you solve them, yet I want to solve them. So, I bought a book on how to form proofs since the Putnam problems involve proving stuff. I wanted to know how to solve these problems, but I lacked foundation (and still do). I did not know where to start (and still do). I did work with the book I bought but eventually I reached that same experience as the Introduction to Algebra book.
之后,我的注意力转移到了其他事情上——普特南数学竞赛的题目(如 http://www.math.niu.edu/~rusin/problems-math/MP1975.html )。我想知道如何解决这些问题!它们对我来说非常神秘(至今仍然如此),因为我不知道解题方法,却又渴望解开它们。由于普特南竞赛的题目涉及证明类内容,我买了一本关于如何构建证明的书。我想学会解决这些问题,但我缺乏必要的知识储备(现在依然如此),也不知道该从何入手(现在依然不知道)。我确实尝试过这本书,但最终还是经历了和《代数导论》一样的感受——枯燥乏味。

For some time, I think I burnt myself out, and I quit solving problems. Currently my head is in chaos with all this overwhelming information in front of me (the internet and masses of books at library), yet not knowing where to start or where to end or am I researching too much on this problem that’s way above my head like the Putnam.
有一段时间,我觉得自己已经精疲力竭,于是停止了做题。目前,面对互联网和图书馆里海量的书籍,这些铺天盖地的信息让我头脑混乱,我不知道该从哪里开始,也不知道该到哪里结束,更不知道自己是否在像普特南这样远超自身能力的问题上研究得太多了。

How do you guys self-study mathematics, especially you very experienced mathematician out there? Do you force yourself to solve dull or uninteresting or easy or unchallenging problems in order to have a firm understanding of things?
大家是如何自学数学的呢?尤其是那些经验丰富的数学家们。为了对知识有更透彻的理解,你们会强迫自己去解决那些枯燥、无趣、简单或没有挑战性的问题吗?

Please mathematicians with great experience I need some guidance, tips, or advice. I did ask my math teacher for advice but she said not to worry, which is not the kind of advice I was looking for.
恳请经验丰富的数学家们给我一些指导、技巧或建议。我曾经向我的数学老师求助,但她只是让我不要担心,这并不是我想要的建议。

Addendum
补充说明

I’m sorry it took me time to respond to this thread. I was sorting thoughts in my head. Now I decided to post my thoughts as it might be helpful for others. This might not be the finest addendum for this thread as it seems to me to be fragmented, but I did my best shot in writing it. Another thing, I may sound egotistic or cocky in this. But remember these are my thoughts, and my thoughts could change in the future.
很抱歉花了这么长时间才回复这个帖子。我一直在整理自己的思绪。现在我决定把我的想法分享出来,因为这可能对其他人也有帮助。这个补充说明可能不是最完美的,在我看来有些零散,但我已经尽力去写了。另外,我在文中的表述可能听起来有些自负或傲慢,但请记住,这些只是我当下的想法,未来可能会发生改变。

First I’d like to thank you guys for responding to this question. Your guys replies are informative and useful. Nevertheless, I think there is no best answer in this thread, although I already chose one based on how agreeable it is to what I’m saying. I think it’s fair to say that advice given in mathematics (or in other fields) is complicated. Why? It’s because everyone is different. Some piece of advice might work for one person but at the same time might not work for the other. In the grand scheme of things, the world is too complicated.
首先,我要感谢大家对这个问题的回应。你们的回复内容丰富且富有帮助。不过,我认为这个帖子中没有所谓的“最佳答案”,尽管我已经根据与我观点的契合程度选择了一个。我认为,数学领域(或其他领域)的建议往往是复杂的。为什么呢?因为每个人都是独一无二的。某条建议对一个人有效,对另一个人可能完全无效。从宏观角度来看,这个世界本身就极为复杂。

Currently I’m ignoring all advice because I think the best advice comes from oneself. In addition, I have been keeping myself an intellectual journal. Whenever a negative emotion appears in my mind, I describe it in my journal. Then I do my best to replace that emotion with a positive emotion. In other words, I redefine how I see things.
目前我没有采纳任何建议,因为我认为最好的建议来自于自己。此外,我一直在写一本“思维日记”。每当心中出现负面情绪时,我会在日记中描述它,然后尽力用积极的情绪去替代它。换句话说,我在重新定义自己看待事物的方式。

For instance, if I approach a math problem that causes me anxiety, I would find a way to change that emotion to a positive one. Suppose I find that other emotion that I want to use to replace the negative emotion, and it’s the emotion of assurance. Specifically, change my negative emotion so I can think that something good will happen. I would say to myself, “although the problem may be tough or frightening, if I do my best to solve it even though I might fail, I will gain better insight into the problem than if I didn’t attempt to solve it.” I know this is cheesy. But this method has worked for me for the past two days. It’s practical for me.
例如,当我遇到一道让我感到焦虑的数学题时,我会想办法将这种负面情绪转化为积极情绪。假设我选择用“笃定感”来替代焦虑——具体来说,就是通过调整心态,让自己相信会有好的结果。我会对自己说:“虽然这道题可能很难,甚至让人望而生畏,但即使我尽力去做后仍然失败了,我也会比不尝试求解获得更深刻的理解。”我知道这听起来有些老套,但在过去的两天里,这个方法对我很有效,它很实用。

In conclusion, this is how I’m approaching mathematics in a general sense:
总之,以下是我目前对待数学的总体方式:

First of all when I do mathematics, I should just do it and approach it. Secondly, I should treat mathematics like a game. It shouldn’t be extremely serious. Curiosity should be my driving force in solving problems. Plus, I should be more playful to gain that “likening/love” as a motivation with the problems even if they’re boring, dull or easy. However, if the problem takes too much energy and time, I’ll think of this nursery rhyme:
首先,当我接触数学时,我会直接行动,主动面对。其次,我会把数学当作一场游戏,不必过于严肃。好奇心应该成为我解决问题的动力。此外,即使遇到枯燥、乏味或简单的题目,我也会以更轻松的心态去对待,培养对这些题目的“喜爱”,并将其作为前进的动力。但如果一道题需要花费过多的精力和时间,我会想起这样一首童谣:

“For every problem under the sun, there’s a solution or there’s none. If there be one, think till you find it. If there be none, then never mind it.” That last bit of the quote I do not take 100% serious. If I put the problem off to the side, I won’t put it off forever. Instead when the time comes when I acquire the necessary knowledge (either be it a month or a year), I will get back to it.
“世间万物皆有解,若无答案便释怀。若有答案细思索,无解之事莫挂怀。”我并不会完全当真对待最后一句。如果我暂时搁置某道题,并不会永远放弃它。相反,当我在未来某个时刻(可能是一个月后,也可能是一年后)掌握了必要的知识,我会重新回到这道题上。

Lastly, I should ignore all given advice on how I should go about doing math (I know that sounds cocky or arrogant). But I am I and they are they. What works for me may not work for them and vice versa. Another thing, is that I found that I was too focused on getting advice in mathematics instead of actually doing mathematics. Here’s a quote that can perhaps add to what I mean:
最后,我会忽略所有关于“如何学习数学”的外部建议(我知道这听起来有些自负或傲慢)。但我就是我,别人就是别人。对我有效的方法可能对他人无效,反之亦然。另外,我发现自己过于专注于寻求数学学习的建议,而忽略了实际去学习数学本身。有一句名言或许能更好地表达我的意思:

“It’s one of the best theories that when people give you advice, they’re really just talking to themselves in the past.” - Austin Kleon
“有一种很棒的观点认为,当人们给你建议时,他们实际上是在和过去的自己对话。”——奥斯汀·克莱恩

You probably got the whole point of my strategy; I’m redefining the way I approach things and getting rid of the negative emotions in my head. This strategy is what I have been doing for the past two days. As of now, this strategy is still working for me.
你们可能已经完全理解了我的策略核心:我正在重新定义自己对待事物的方式,并摆脱心中的负面情绪。过去两天我一直坚持这样做,到目前为止,这个策略对我仍然有效。

Again, I want to emphasize these are my thoughts, and my thoughts are pretty messy. Do not take it all too serious what I wrote as an overall character of me. Feel free to critique what I wrote as well. I just wanted to share it as it might help other people.
我再次强调,这些只是我当下的想法,而且有些杂乱无章。请不要将我所写的内容完全视为我的整体性格写照,也欢迎大家对我的文字提出批评指正。我只是想把这些想法分享出来,希望能帮助到其他人。

edited Nov 20, 2013 at 20:27
asked Nov 18, 2013 at 3:11
user93971

Gaps in your knowledge? Do you realize that in “solving” the problem, you have to understand every definition that the problem requires? How exactly is there a lack of foundation?
知识存在漏洞?你是否意识到,在“解决”一个问题时,你必须理解该问题所涉及的每一个定义?所谓的缺乏基础具体体现在哪里?

– Don Larynx
Commented Nov 18, 2013 at 3:12

If you find a book boring when studying independently, shove it under your bed or stick it in the library’s donation pile and go try a different one. There are loads of lousy math books out there. Get one of the good ones.
如果你在自学时发现一本书很无聊,就把它塞到床底下,或者扔进图书馆的捐赠堆里,然后换一本试试。市面上有很多糟糕的数学书,找一本好的来读。

– dfeuer
Commented Nov 18, 2013 at 3:22

I only have one small thing to add: self studying should be driven by your interest. Try out some of the books recommended in the answers below, but don’t stick with them if you find them boring. Grinding through material that you don’t really like much is what classwork is for. Find something that you are interested in studying, something that really fascinates you, and make that what you self study.
我只想补充一点:自学应该由兴趣驱动。你可以试试下面回答中推荐的一些书籍,但如果发现它们很无聊,就不要勉强自己坚持下去。钻研自己并不真正喜欢的内容是课堂学习的任务。找到你真正感兴趣、真正能吸引你的东西,把它作为你的自学内容。

By the way, many people who love problem solving also love combinatorics. You may want to try out a book on that first.
顺便说一句,很多喜欢解题的人也喜欢组合数学。你或许可以先试试相关的书籍。

– Alexander Gruber♦
Commented Nov 18, 2013 at 5:37

Answers

Do the things you like. If something you’re doing isn’t fun, stop, and do something else.
做你喜欢的事。如果你正在做的事情没有乐趣,就停下来,去做别的事情。

Mathematics is hard enough that if you are doing it it should be because you enjoy it. There is no point in doing it to become a mathematician if you don’t enjoy it; you’d be in the position of someone who is trying to become a rabbi, but isn’t Jewish, or maybe someone who wants to become a professional violinist but doesn’t like playing the violin. It’s not just silly, it’s insane.
数学本身已经足够难了,所以你学习它的唯一理由应该是热爱。如果不喜欢数学,却为了成为数学家而学习,那是毫无意义的——这就好比一个非犹太人想成为拉比,或者一个不喜欢拉小提琴的人想成为专业小提琴家。这不仅愚蠢,更是不切实际的。

If you find some topic uninteresting, skip it. Perhaps someday it will become interesting to you, perhaps because you need it to solve some problem you want to solve, and you can learn it then. Or perhaps it never grabs you; so what? You aren’t going to run out of things to learn. (Or if you do run out of subjects that seem interesting, perhaps you should take that as a sign that you don’t really want to be studying mathematics.)
如果你发现某个主题无趣,就跳过它。或许有一天,它会变得对你有吸引力——可能是因为你需要用它来解决某个你想解决的问题,到那时再学习也不迟。又或许它永远不会吸引你,那又如何?值得学习的东西无穷无尽。(如果有一天你再也找不到感兴趣的数学主题了,或许这正是在告诉你,你并不真正想学习数学。)

If you find you’re burned out and you don’t want to do any more problems, stop and do other things for a while. I would not be surprised if you found that after a few weeks off you discovered you were no longer burned out, and you wanted to start again. At sixteen, a few weeks or months seems like a long time. But when you look back on it, it seems a lot less important. When I was a teenager I loved programming the computer and I did it all the time. But I burned out on computer programming when I was sixteen and stopped doing it for a year and a half. Then one day it was interesting again and I went back to programming. My 18-month vacation did not prevent me from having a productive career as a programmer, or from becoming a well-known expert on computer programming. Do I look back on my life and wish I had that extra 18 months, do I wonder if I wouldn’t have been more successful with 39 years of practice instead of only 37½? Of course I don’t. Instead I look back and it seems that taking a year-and-a-half vacation from programming was most likely the right thing to do at the time.
如果你感到精疲力竭,不想再做任何题目,就停下来,先去做些别的事情。几周后,当你发现自己已经摆脱疲惫,重新燃起学习热情时,不要感到惊讶。对于 16 岁的你来说,几周或几个月似乎很漫长,但当你回首往事时,会发现这段时间其实并不重要。我十几岁时非常喜欢计算机编程,几乎无时无刻不在做这件事。但在 16 岁那年,我对编程感到厌倦,整整一年半没有碰它。后来有一天,我又重新对编程产生了兴趣,于是再次拾起了它。那段 18 个月的“假期”并没有阻碍我成为一名有成就的程序员,也没有影响我成为计算机编程领域的知名专家。我会回顾人生,遗憾自己少了那 18 个月的练习时间吗?会想如果有 39 年的实践经验,而不是 37 年半,会不会更成功吗?当然不会。相反,我觉得当时暂停编程、休息一年半,很可能是一个正确的决定。

But suppose you did burn out and didn’t want to solve math problems ever again? What then? All I can think is “So what?” The world would have to do without your mathematical contributions. That’s okay; you can find something else to contribute instead.
但假设你这次彻底厌倦了数学,再也不想解任何数学题了,那又会怎样?我能想到的只有一句话:“那又如何?”这个世界或许会缺少你的数学贡献,但这没关系——你可以在其他领域发光发热。

edited Nov 18, 2013 at 19:07
answered Nov 18, 2013 at 3:51
MJD

The problem with my original approach in mathematics was that it was undisciplined. It was do whatever that interests me. But I wanted to solve the Putnam problems. I thought I needed to be more disciplined when I studied. I worked through all the problems through each section in a book until I reached chapter 2.3; it involved changing notation from one form to another, a thing that isn’t interesting to me. However, should I spend time making the uninteresting problems interesting? Someone told me in Cognitive science liking stuff is malleable/flexible. There’s nothing to truly like, he said.
我最初的数学学习方法存在一个问题:缺乏系统性,只是随心所欲地做自己感兴趣的事。但我想解决普特南竞赛的题目,所以我认为学习时需要更有纪律性。我逐节做完一本书中的所有题目,直到第 2.3 章——这一章涉及将一种符号形式转换为另一种形式,我对此毫无兴趣。不过,我是否应该花时间让这些无趣的题目变得有趣呢?有人从认知科学的角度告诉我,喜好是可塑的、灵活的。他说,世界上并不存在真正“天生喜欢”的东西。

– user93971
Commented Nov 18, 2013 at 13:52

I think “get a better book” is good advice. Something that has sometimes worked for me is to go to the library, take down six books on the same subject, and spend ten or fifteen minutes with each one to find the one I like best. Also, have you seen Terry Tao’s little book on problem solving? Tao had a gold medal in the 1988 IMO.
我认为“找一本更好的书”是个好建议。我有时会这样做:去图书馆,找出六本同一主题的书,每本花 10 到 15 分钟翻阅,然后选出最适合自己的那本。另外,你看过陶哲轩的那本关于解题的小书吗?陶哲轩曾获得 1988 年国际数学奥林匹克竞赛(IMO)金牌。

– MJD
Commented Nov 18, 2013 at 14:32

It sounds like the mathematics you’ve been exposed to so far has been very problem/solution driven. If that’s not floating your boat at the moment, why not try some math that is theorem/proof driven? Here are a few recommendations.
听起来你目前接触的数学内容都是以“问题-解答”为导向的。如果这种模式现在对你没有吸引力,为什么不尝试一些以“定理-证明”为导向的数学呢?以下是一些推荐书籍:

  1. A Book of Abstract Algebra
    《抽象代数入门》

  2. Classic Set Theory
    《经典集合论》

  3. How to Think Like A Mathematician
    《如何像数学家一样思考》

  4. How to Prove It
    《如何证明》

I’ve read a fair chunk of books 1 and 2, and they’re great! They might be a bit advanced for a sixteen year old with no background in proof, so perhaps a better starting point would be books 3 and 4. I haven’t read them, but the amazon reviews speak for themselves.
我已经读了第 1 本和第 2 本的大部分内容,它们非常棒!对于一个没有证明基础的 16 岁学生来说,这两本书可能有点难,所以或许第 3 本和第 4 本是更好的起点。我虽然没读过这两本,但亚马逊上的评价已经说明了一切。

Hope that helps!
希望这些建议能帮到你!

Remark

补充说明

I’ve also heard that introductory number theory books are great for people in your situation; that is, bright high school students who are looking for a bit more of a “kick” and a bit more insight. Perhaps someone else will be able to recommend something in this domain.
我还听说,数论入门书籍非常适合你这种情况的学生——聪明的高中生,渴望获得更多挑战和更深层次的理解。或许其他人会推荐这个领域的相关书籍。

edited Jun 12, 2020 at 10:38
answered Nov 18, 2013 at 3:31
goblin GONE


Bringing Mathematics Education Into the Algorithmic Age

将数学教育带入算法时代

Newcomb Greenleaf
Department of Computer Science Columbia University, New York, N. Y. 10027
newcomb@cs.columbia.edu

Abstract

摘要

We began from the observation that most of our students find algorithms easy and natural and proofs difficult and obscure, and are totally unaware of the close relationship between algorithms and proofs. This observation led to the hypothesis that part of the problem lay in the fact that the students had been born into the algorithmic age, which their mathematics courses had largely yet to enter. This paper explores various ways in which mathematics courses can be made more algorithmic, both in style and in content. Particular attention will be paid to the term non-computable function, which will be seen as oxymoronic. An algorithmic explanation will be developed, particularly for the busy beaver function. We shall also give an algorithmic analysis of Cantor’s diagonal method.
我们的研究始于一个观察:大多数学生认为算法简单自然,而证明则晦涩难懂,且完全没有意识到算法与证明之间的密切联系。这一观察引出了一个假设:部分问题源于学生出生在算法时代,而他们的数学课程在很大程度上尚未适应这一时代。本文探讨了使数学课程在风格和内容上更具算法性的多种方法。我们将特别关注“不可计算函数”这一术语,认为其本身存在矛盾。我们将给出一种算法式的解释,尤其是针对忙碌的海狸函数,并对康托尔对角线法进行算法分析。

1. Learning Mathematics in the Algorithmic Age

1. 算法时代的数学学习

The observations that follow are based on my own experience in teaching a variety of courses involving both theory and programming at Columbia University, on the comments (and complaints) of several of my colleagues about our students, and on numerous anecdotal reports from teachers at other institutions.
以下观察基于我在哥伦比亚大学教授多门涉及理论与编程的课程的个人经验、多位同事对学生的评价(及抱怨),以及来自其他机构教师的大量轶事报告。

Our good students are very good algorithmists. They find the concept of an algorithm a natural one and delight in understanding the subtleties of intricate algorithms. When they write programs, they take pride not just in the correctness and robustness of their code, but also in its intelligibility and aesthetic appearance.
我们的优秀学生都是出色的算法设计者。他们认为算法的概念与生俱来,乐于理解复杂算法的精妙之处。在编写程序时,他们不仅为代码的正确性和健壮性感到自豪,也为其易懂性和美观性而骄傲。

With a few exceptions, these same students are not good mathematicians. After four semesters of calculus they have only the foggiest notions of mathematical analysis. They find the notion of mathematical proof uninteresting and unintelligible. While they have seen proofs by mathematical induction in a variety of courses, they are still generally unable to do even the simplest proofs by mathematical induction.
但除少数例外,这些学生并非优秀的数学家。经过四个学期的微积分学习,他们对数学分析仍只有模糊的概念。他们觉得数学证明枯燥乏味、难以理解。尽管在多门课程中接触过数学归纳法证明,但他们通常仍无法完成哪怕是最简单的数学归纳法证明。

In view of this dichotomy, it is not surprising that they see no close connection between algorithms and proofs. They are capable of giving cogent informal arguments for the correctness of their programs, but they are generally skeptical and rather fearful of the subject of program verification (which, indeed, is little practiced at Columbia). Almost never have they been exposed to the idea that mathematics can be done algorithmically or constructively. They find this idea both intriguing and astonishing.
鉴于这种二分法,他们看不到算法与证明之间的密切联系也就不足为奇了。他们能够为程序的正确性给出有说服力的非正式论证,但通常对程序验证这一主题持怀疑态度,甚至感到畏惧(事实上,哥伦比亚大学几乎不开展相关实践)。他们几乎从未接触过“数学可以通过算法或构造性方式进行”这一理念,对此既好奇又惊讶。

It seems natural to conjecture that the problem lies, in part, in the failure of instruction in mathematics to adjust and develop to living in the age of algorithms. If mathematics were presented more algorithmically, then it could build on the students’ understanding of algorithms, and perhaps students would take to it with more ease and enthusiasm.
我们自然会推测,部分问题在于数学教学未能适应算法时代的发展。如果数学教学能更具算法性,就能以学生对算法的理解为基础,或许学生能更轻松、更热情地投入到数学学习中。

After a brief discussion of the algorithm concept and the way in which it has entered into the center of our thought, I will present several suggestions on ways in which mathematics instruction can be made more algorithmic, with some focus on the first course in computer theory.
在简要讨论算法概念及其如何成为我们思想核心之后,我将提出若干建议,说明如何使数学教学更具算法性,其中将重点关注计算机理论的入门课程。

2. The Algorithm Concept

2. 算法概念

The name “the Euclidean algorithm” may give the misleading impression that the concept of an algorithm has been securely and explicitly rooted in our mathematical thought for many centuries. In fact, the word algorithm acquired its modern meaning only half a century ago. Unabridged dictionaries of the 1930’s define algorithm only as an “erroneous refashioning” of algorism. (Algorists used the ten digits for computing, instead of an abacus). This art was brought to Europe by the Latin translation of a text by al-Khwarizmi, the eponymous ninth century mathematician of Baghdad. According to the new Oxford English Dictionary of 1989, the first modern use of the word was in the classic 1938 number theory text of Hardy and Wright, where the nomenclature “the Euclidean algorithm” was introduced. While there are doubtless earlier occurrences missed by the OED, the term could not then have been in common parlance. Now it has become so central that Knuth has proposed algorithmics as the best name for the discipline of computer science [20].
“欧几里得算法”这一名称可能会给人一种误导,认为算法概念几个世纪以来一直牢固且明确地植根于我们的数学思想中。事实上,“algorithm”一词直到半个世纪前才获得其现代含义。20世纪30年代的完整版词典仅将其定义为“algorism”(十进制计数法)的“错误重构”(十进制计数法使用者用十个数字进行计算,而非算盘)。这一方法通过9世纪巴格达数学家花拉子米(al-Khwarizmi)的著作拉丁文译本传入欧洲,“algorithm”一词也源于他的名字。根据1989年新版《牛津英语词典》,该词的首次现代用法出现在哈代(Hardy)和赖特(Wright)1938年的经典数论教材中,书中首次提出了“欧几里得算法”这一命名。尽管《牛津英语词典》无疑遗漏了更早的用法,但该术语在当时不可能被广泛使用。如今,它已成为核心概念,克努特(Knuth)甚至提议将“算法学”(algorithmic)作为计算机科学这一学科的最佳名称[20]。

I shall not attempt an extended discussion of the nature of algorithms. It is a subject to which philosophers have yet to pay sufficient attention. Like all foundational terms, the algorithm concept is difficult to define. A standard discussion occurs in Knuth’s Fundamental Algorithms [19], pp. 1-9, where algorithms are characterized in terms of five properties: finiteness, definiteness, input, output, and effectiveness. Many interesting insights about the algorithm concept can be found in the papers presented at the symposium honoring al-Khwarizmi, held near the place of his birth on its 1200-th anniversary [15].
我不会试图深入讨论算法的本质——这是一个哲学家尚未给予足够关注的主题。与所有基础术语一样,算法概念难以定义。克努特在《基本算法》[19]第1-9页对此进行了标准论述,将算法的特征概括为五个属性:有限性、确定性、输入、输出和有效性。在纪念花拉子米诞辰1200周年的研讨会上(于其出生地附近举办),多篇论文对算法概念提出了许多有趣的见解[15]。

Associated with the algorithm concept is a powerful new language of algorithms and data structures. Since Euclid, mathematicians have used algorithms, but only recently have systematic languages for algorithms been developed. And only very recently has an evident quorum of mathematicians, through their programming experience, become fluent in higher-level algorithmic languages. A Pascal-like pseudo-code has become a new lingua franca and is used in many recent texts on discrete mathematics. There has been much discussion of the proper mathematics prerequisites for computing courses. Soon we may expect to see mathematics courses with a computer science prerequisite, since students master the language of algorithms through learning to program [17].
与算法概念相关的是一种强大的新语言——算法与数据结构语言。自欧几里得以来,数学家就一直在使用算法,但直到最近才发展出系统的算法语言。而且,直到非常晚近,才有相当数量的数学家通过编程经验,熟练掌握了高级算法语言。一种类帕斯卡伪代码已成为新的通用语言,被用于近年来许多离散数学教材中。关于计算机课程应具备的数学先修知识,人们已有诸多讨论。不久之后,我们可能会看到以计算机科学为先修课程的数学课程,因为学生通过学习编程来掌握算法语言[17]。

Of course, we have had the languages of Turing machines and recursive functions for half a century. While these precise formalisms have made their mark on our thought, they are at the level of assembly or machine language, and, as Martin-Löf and others have shown us, mathematics might best be regarded as a very high level programming language [22].
当然,半个世纪以来,我们已有图灵机和递归函数语言。尽管这些精确的形式化方法对我们的思想产生了深远影响,但它们相当于汇编语言或机器语言;而正如马丁-洛夫(Martin-Löf)等人所指出的,数学或许最适合被视为一种非常高级的编程语言[22]。

There is a complex symbiotic relationship between algorithm and proof. In computer science proofs are used to verify algorithms. Indeed, any algorithm must be supported by some form of proof to be believed. Such proofs often consist of a very informal argument buttressed by testing of special cases, but many workers in program verification argue that a program should be a proof that can be compiled [2, 10].
算法与证明之间存在复杂的共生关系。在计算机科学中,证明被用于验证算法。事实上,任何算法都必须有某种形式的证明作为支撑才能被采信。这类证明通常包括非正式论证,并辅以特殊案例测试,但许多程序验证领域的研究者认为,程序本身应是可编译的证明[2, 10]。

On the other hand, mathematicians often use algorithms in their proofs, and many proofs are totally algorithmic, in that the triple [assumption, proof, conclusion] can be understood in terms of [input data, algorithm, output data]. Such proofs are often known as constructive, a term which provokes endless unfortunate arguments about ontology.
另一方面,数学家经常在证明中使用算法,许多证明本身就是完全算法化的——即“假设-证明-结论”这一三重结构可以被理解为“输入数据-算法-输出数据”。这类证明通常被称为“构造性证明”,但这一术语引发了无数关于本体论的不必要争论。

An interesting discussion of the relation between algorithms and proofs occurs in Knuth’s review [20] of Bishop’s Foundations of Constructive Analysis [4]:
克努特在评论毕晓普(Bishop)的《构造性分析基础》[4]时,对算法与证明的关系进行了有趣的探讨[20]:

The interesting thing about this book is that it reads essentially like ordinary mathematics, yet it is entirely algorithmic in nature if you look between the lines.
这本书的有趣之处在于,它读起来本质上与普通数学无异,但如果深入细节就会发现,其本质完全是算法化的。

Knuth goes on to analyze the algorithmic nature of Bishop’s proof of the Stone-Weierstrass theorem in great detail, even translating it into pseudocode, and noting that:
克努特进一步详细分析了毕晓普关于斯通-魏尔斯特拉斯定理证明的算法本质,甚至将其转化为伪代码,并指出:

I want to stress that the proof is essentially an algorithm; the algorithm takes any constructively given compact set X X X and continuous function f f f and tolerance ϵ \epsilon ϵ as input, and it outputs a polynomial that approximates f f f to within ϵ \epsilon ϵ on all points of X X X. Furthermore the algorithm operates on algorithms, since f f f is given by an algorithm of a certain type, and since real numbers are essentially algorithms themselves.
我想强调的是,这个证明本质上是一种算法:该算法将任何构造性给定的紧集 X X X、连续函数 f f f 和容差 ϵ \epsilon ϵ 作为输入,输出一个多项式,该多项式在 X X X 的所有点上都能以 ϵ \epsilon ϵ 精度逼近 f f f。此外,该算法是对算法进行操作的——因为 f f f 由某种特定类型的算法给出,而实数本身本质上也是算法。

It seems that we are seeing the emergence of a new concept, of which proof and algorithm are but two aspects. Michael Beeson recently put it nicely (in the context of a discussion of Prolog), [3]:
我们似乎正在见证一个新概念的出现,证明和算法只是其两个方面。迈克尔·比森(Michael Beeson)最近在讨论Prolog语言时对此有精妙的表述[3]:

The flow of information seems now to be logic, now to be computation. Like waves and particles, logic and computation are metaphors for different aspects of some underlying unity.
信息的流动时而表现为逻辑,时而表现为计算。如同波与粒子,逻辑和计算是某种底层统一性不同方面的隐喻。

I have no good candidate for a name for this underlying unity (neither verified algorithm nor constructive proof does it justice). It should be remarked that the coming together of the concepts of algorithm and proof creates two tensions. The pull to make proofs more like algorithms is the subject of this article. I hope to discuss the reverse pull, which manifests in Prolog and logic programming generally, in a subsequent paper.
我无法为这一底层统一性找到一个合适的名称(“已验证算法”或“构造性证明”都不足以概括)。需要指出的是,算法与证明概念的融合产生了两种张力:使证明更接近算法的张力是本文的主题;而另一种相反的张力(体现在Prolog和一般逻辑编程中),我希望在后续论文中进行讨论。

For our purposes, this superficial discussion of the relationship between algorithms and proofs will do. The important point is that the explicit notion of an algorithm has become central in mathematical thought only recently. While our students are at home with algorithms and algorithmic languages, instruction in mathematics is only beginning to adjust to the new reality. In particular, almost never do mathematics texts take advantage of the new algorithmic literacy to explain proofs in terms of algorithms.
就我们的目的而言,对算法与证明关系的这种表层讨论已经足够。关键在于,算法的明确概念直到最近才成为数学思想的核心。虽然我们的学生熟悉算法和算法语言,但数学教学才刚刚开始适应这一新现实。尤其是,数学教材几乎从未利用学生新具备的算法素养,以算法的方式解释证明。

3. Algorithmic Style

3. 算法风格

Through our experience in writing computer programs, we have gradually developed a distinctive and effective style for presenting algorithms. While this style has much in common with mathematics, it departs radically from traditional mathematical style in some ways. This is strikingly evident in the different approaches to names and symbols. Mathematicians have generally used single characters for symbols. There is good reason for this, since it leads to brevity and allows complex formulas to be written concisely. But this style demands of the reader that she remember the meanings of all of the symbols, which do not have mnemonic names, and my students generally are unable and/or unwilling to read material written in this style.
通过编写计算机程序的经验,我们逐渐形成了一种独特且有效的算法呈现风格。这种风格虽与数学有诸多共通之处,但在某些方面与传统数学风格存在根本性差异——这一点在符号命名方式上体现得尤为明显。数学家通常使用单字符符号,这有其合理之处:简洁明了,能使复杂公式的书写更为凝练。但这种风格要求读者记住所有无记忆辅助意义的符号含义,而我的学生通常无法或不愿阅读此类风格的材料。

Computing also puts a high value on brevity. Good programming style dictates that procedures be fairly short, but this is not generally achieved by using single-character symbols. Rather, symbols are generally words or word fragments, chosen for mnemonic value. Brevity is achieved through procedural abstraction, by giving each procedure a relatively simple task, and using many procedures in a single program.
计算领域同样重视简洁性。良好的编程风格要求过程(函数)应相当简短,但这通常不是通过使用单字符符号实现的。相反,符号通常是具有记忆辅助功能的单词或单词片段。简洁性通过过程抽象实现:为每个过程分配相对简单的任务,并在单个程序中组合使用多个过程。

Good programming style also pays careful attention to the layout of the program on the page or screen. I regularly teach the Scheme dialect of LISP to novice programmers. A great deal of credit for the success of this enterprise goes to the pretty-printing mechanism of the editor which lays out the programs in a way which both illustrates the structure and is aesthetically pleasing. Here is the first substantial procedure which my students see, adapted from [1], which uses Newton’s method to compute the square root of a number x x x. The simple helping procedures square and average are defined elsewhere.
良好的编程风格还注重程序在页面或屏幕上的排版。我经常向新手程序员教授LISP语言的Scheme方言。这一教学工作的成功在很大程度上归功于编辑器的美化打印机制——它以既清晰展示结构又美观的方式排版程序。以下是我的学生接触到的第一个完整过程,改编自[1],该过程使用牛顿法计算数字 x x x 的平方根(简单的辅助过程 square(平方)和 average(平均)已在其他地方定义):

(define (sqrt x tolerance)
  (define (sqrt-iter guess)
    (define (improve)
      (average guess (/ x guess)))
    (define (good-enough?)
      (< (abs (- (square guess) x)) tolerance))
    (if (good-enough?)
        guess
        (sqrt-iter (improve))))
  (sqrt-iter 1.0))

While this is a challenging procedure for the second week of a first course, the combination of mnemonic names and pretty-printing (along with the simple syntax of Scheme) makes it accessible to students. Now consider how inaccessible the same procedure becomes when mnemonic names are replaced by single letter symbols:
对于入门课程第二周的学生来说,这一过程具有一定挑战性,但记忆辅助命名、美化排版(以及Scheme简洁的语法)使其易于理解。现在,我们看看如果将记忆辅助名称替换为单字符符号,同一个过程会变得多么晦涩:

(define (s x t)
  (define (i g)
    (define (p)
      (a g (/ x g)))
    (define (g?)
      (< (abs (- (q g) x)) t))
    (if (g?)
        g
        (i (p))))
  (i 1.0))

Had the students been presented with the latter version, which mimics the mathematical style of conciseness, their reaction would have been quite different. Instead of loving the course, they might have dropped it.
如果向学生展示的是后一个模仿数学简洁风格的版本,他们的反应肯定会截然不同——他们可能不会喜欢这门课程,甚至会放弃学习。

A glaring example of the failure of mathematics instruction to make the subject algorithmic occurs in the elementary differential calculus, which is still generally presented as a large collection of derivative formulas. Of course, these formulas are intended to be used as the base cases and recursive operations of a grand recursive derivative algorithm, which, for want of a proper language, is not made explicit (and therefore never really verified).
数学教学未能实现算法化的一个明显例子是初等微分学——它至今仍通常被呈现为一整套导数公式的集合。当然,这些公式本应作为一个宏大的递归导数算法的基例和递归操作,但由于缺乏合适的语言,该算法并未被明确呈现(因此也从未真正得到验证)。

The derivative algorithms can be cast in two different forms. If the chain rule is made an explicit recursive operation, then there will be a large number of base case formulas, such as:
导数算法可以分为两种形式。如果将链式法则作为明确的递归操作,那么会有大量基例公式,例如:
D ( sin ⁡ x ) = cos ⁡ x D(\sin x) = \cos x D(sinx)=cosx

If the chain rule is built into most derivative formulas, then the sine formula will appear as a recursive operation, corresponding to the formula:
如果将链式法则融入大多数导数公式,那么正弦函数的导数公式将表现为递归操作,对应于:
D ( sin ⁡ u ) = ( cos ⁡ u ) ∗ D u D(\sin u) = (\cos u) * D u D(sinu)=(cosu)Du

and there will be two base cases which tell us that the derivative of a constant is 0 and the derivative of the identity function is 1. The student of calculus is expected not merely to learn the various formulas, but primarily to understand the operation of the recursive algorithm, which never appears explicitly.
此时仅有两个基例:常数的导数为 0,恒等函数的导数为 1。微积分学生不仅需要学习各种公式,更重要的是理解那个从未明确呈现的递归算法的运作方式。

We can hope that tomorrow’s calculus texts will express the derivative algorithm explicitly in a (formal or informal) algorithmic language, as is already done in programming texts such as [1]. Here is a simple implementation of the derivative algorithm in the Scheme programming language (any programming language supporting recursion would do), adapted from [1], which takes the derivative of an expression exp with respect to var. Note that the first two cases are the only base cases. The various constructors, selectors, and predicates, such as make-sum, multiplicand, and constant? are defined elsewhere. This simple version handles only sums, products and sines:
我们期望未来的微积分教材能以(形式化或非形式化的)算法语言明确表达导数算法,就像[1]等编程教材所做的那样。以下是导数算法在Scheme语言中的简单实现(任何支持递归的编程语言都可实现),改编自[1],该过程计算表达式 exp 关于变量 var 的导数。注意,前两个情况是仅有的基例(各种构造函数、选择函数和谓词,如 make-sum(构造和)、multiplicand(被乘数)和 constant?(常数判断)已在其他地方定义)。这个简单版本仅处理和、积和正弦函数:

(define (deriv exp var)
  (cond ((constant? exp) 0)
        ((variable? exp)
         (if (same-variable? exp var) 1 0))
        ((sum? exp)
         (make-sum (deriv (addend exp) var)
                   (deriv (augend exp) var)))
        ((product? exp)
         (make-sum
          (make-product (multiplier exp)
                        (deriv (multiplicand exp) var))
          (make-product (deriv (multiplier exp) var)
                        (multiplicand exp))))
        ((sine? exp)
         (make-product (make-cosine (arg exp))
                       (deriv (arg exp) var)))
        (else (error "Unknown expression type -- DERIV" exp))))

When the derivative algorithm assumes its rightful place as the primary explicit structure of differential calculus, there is a welcome gain in clarity, and also a subtle but profound shift of meaning. The proofs of the various derivative formulas are now part of the verification of the algorithm. They prove the correctness of an algorithm rather than the truth of a theorem. These considerations are amplified in [25].
当导数算法作为微分学的核心明确结构占据其应有的位置时,不仅清晰度会显著提升,还会发生一种微妙但深刻的意义转变:各种导数公式的证明现在成为算法验证的一部分——它们证明的是算法的正确性,而非定理的真实性。这一观点在[25]中有更详细的阐述。

We can summarize this discussion by enunciating Four Marks of Algorithmic Style:
通过以上讨论,我们可以总结出算法风格的四个特征:

  1. Mnemonics: Use mnemonic names for symbols, and achieve brevity through abstraction.

    记忆辅助性:为符号使用具有记忆辅助功能的名称,通过抽象实现简洁性。

  2. Explicitness: Make the algorithms explicit. Identify input and output and check the effectiveness of the algorithm. When appropriate, pay attention to questions of efficiency and feasibility.

    明确性:明确呈现算法,指明输入和输出,检查算法的有效性;必要时关注效率和可行性问题。

  3. Language: Use an appropriate algorithmic language, which can be pseudocode rather than a formal programming language.

    语言适配性:使用合适的算法语言,可为伪代码而非形式化编程语言。

  4. Primacy: Make algorithms the primary structures when appropriate. For instance, the chapter of a calculus text dealing with differentiation could be called “The Derivative Algorithm.”

    核心性:在适当时将算法作为核心结构。例如,微积分教材中关于微分的章节可命名为“导数算法”。

We will illustrate these principles further by considering an example from the first course in computing theory. This course is traditionally called “Computability,” a name which I feel is highly inappropriate, for reasons to appear below. A far better title would be “Languages, Grammars, and Machines.”
我们将通过计算机理论入门课程的一个例子进一步说明这些原则。该课程传统上被称为“可计算性”,但我认为这个名称非常不合适(原因如下),一个好得多的标题是“语言、语法与机器”。

I have taught Computability on numerous occasions at Columbia. The first time I used the excellent traditional text of Lewis and Papadimitriou [21]. While I found the book to be clear and comprehensive, my students found it almost completely unreadable. They would open it only when problems were assigned, and then would skim backwards from the problems to see if they could find a relevant formula. Now this is what students have been doing with mathematics texts for many years, but it is not optimal for learning. I then heard of the text by Daniel Cohen, which takes a very different approach [9]. At first I was skeptical, but after giving it a try became an enthusiastic booster of Cohen’s text. True, Cohen takes 800 pages to cover what Lewis and Papadimitriou do in less than half of their 400 pages. But students found the book a joy to read, and in reading it they acquired a much better understanding than they had when I had used a traditional text, and they went on to distinguish themselves in more advanced courses using traditional texts.
我在哥伦比亚大学多次教授“可计算性”课程。第一次授课时,我使用了刘易斯(Lewis)和帕帕迪米特里欧(Papadimitriou)的优秀传统教材[21]。虽然我认为这本书清晰全面,但我的学生却觉得它几乎完全无法阅读——他们只在布置作业时才会翻开书,然后从作业题目倒着浏览,试图找到相关公式。多年来,学生们对待数学教材一直如此,但这并非最佳学习方式。后来,我听说了丹尼尔·科恩(Daniel Cohen)的教材,其采用了截然不同的方法[9]。起初我持怀疑态度,但尝试使用后,我成为了科恩教材的热心推崇者。诚然,科恩用800页篇幅涵盖的内容,刘易斯和帕帕迪米特里欧在其400页教材的不到一半篇幅中就完成了。但学生们觉得科恩的书读起来很愉快,通过阅读获得了比使用传统教材时深刻得多的理解,并且在后续使用传统教材的高级课程中表现出色。

The text of Lewis and Papadimitriou is written in a traditional mathematical style and displays none of the marks of algorithmic style. If we examine Cohen’s book in light of the four marks, we see that he is very careful to use well-chosen mnemonic names. Indeed, the book contains virtually no traditional-looking mathematical formulas which students new to the subject find so opaque. He always presents his proofs as algorithms and continually points this out. But he does not use any special language for algorithms, preferring to present them in lengthy English descriptions. Of course, this allows the instructor to ask students to summarize various algorithms in pseudocode. And while the algorithms are explicit, they are embedded within the proofs of theorems, which remain the primary structures. So Cohen exhibits two of the four marks to a high degree.
刘易斯和帕帕迪米特里欧的教材采用传统数学风格,完全不具备算法风格的特征。如果从算法风格的四个特征来审视科恩的书,我们会发现他非常注重使用精心选择的记忆辅助名称——书中几乎没有传统数学教材中那种让新手学生感到晦涩难懂的公式。他总是将证明作为算法呈现,并不断强调这一点。但他没有使用任何专门的算法语言,而是倾向于用详细的英文描述来呈现算法——这当然允许教师要求学生用伪代码总结各种算法。此外,尽管算法是明确的,但它们被嵌入到定理证明中,定理仍是核心结构。因此,科恩在四个特征中的两个方面表现突出。

To highlight the difference between Cohen’s text and that of Lewis and Papadimitriou, I will present the beginning of a crucial proof from each text. The proof involves showing that any deterministic finite automaton (DFA) there exists an equivalent regular expression. Lewis and Papadimitriou start like this:
为了突出科恩教材与刘易斯、帕帕迪米特里欧教材的差异,我将呈现两本书中一个关键证明的开头部分——该证明旨在说明任何确定性有限自动机(DFA)都存在等价的正则表达式。刘易斯和帕帕迪米特里欧的证明开头如下:

Let M = ( K , Σ , δ , s , F ) M = (K, \Sigma, \delta, s, F) M=(K,Σ,δ,s,F) be a deterministic finite automaton; we need to show that there is a regular language R R R such that R = L ( M ) R = L(M) R=L(M). We represent L ( M ) L(M) L(M) as the union of many (but a finite number of) simple languages. Let K = { q 1 , ⋯   , q n } K = \{ q_1, \cdots, q_n \} K={q1,,qn}, s = q 1 s = q_1 s=q1. For i , j = 1 , ⋯   , n i, j = 1, \cdots, n i,j=1,,n and k = 1 , ⋯   , n + 1 k = 1, \cdots, n+1 k=1,,n+1 we let R ( i , j , k ) R(i, j, k) R(i,j,k) be the set of all strings in Σ ∗ \Sigma^* Σ which drive M M M from q i q_i qi to q j q_j qj without passing through any state numbered k k k or greater.
M = ( K , Σ , δ , s , F ) M = (K, \Sigma, \delta, s, F) M=(K,Σ,δ,s,F) 为确定性有限自动机;我们需要证明存在正则语言 R R R 使得 R = L ( M ) R = L(M) R=L(M)。我们将 L ( M ) L(M) L(M) 表示为多个(但有限个)简单语言的并集。设 K = { q 1 , ⋯   , q n } K = \{ q_1, \cdots, q_n \} K={q1,,qn} s = q 1 s = q_1 s=q1。对于 i , j = 1 , ⋯   , n i, j = 1, \cdots, n i,j=1,,n k = 1 , ⋯   , n + 1 k = 1, \cdots, n+1 k=1,,n+1,令 R ( i , j , k ) R(i, j, k) R(i,j,k) Σ ∗ \Sigma^* Σ 中所有能使 M M M 从状态 q i q_i qi 转移到 q j q_j qj 且不经过编号大于等于 k k k 的状态的字符串集合。

The proof is off to an economical start. It will be completed in less than a page. But because of the density of non-mnemonic notation, and the complete lack of an algorithmic framework, few beginning students will even attempt to read it, let alone come to understand it.
这个证明的开头简洁凝练,全文不到一页就能完成。但由于大量非记忆辅助符号的使用,且完全缺乏算法框架,几乎没有新手学生会尝试阅读它,更不用说理解它了。

In marked contrast, Cohen starts off as follows:
相比之下,科恩的证明开头如下:

The proof of this part will be by constructive algorithm. This means that we present a procedure that starts out with a transition graph and ends up with a regular expression that defines the same language. To be acceptable as a method of proof, any algorithm must satisfy two criteria. It must work for every conceivable TG, and it must guarantee to finish its job in a finite time (in a finite number of steps). For the purposes of theorem-proving alone, it does not have to be a good algorithm (quick, least storage used, etc.). It just has to work in every case.
本部分的证明将通过构造性算法完成。这意味着我们将呈现一个过程:以转移图为输入,最终输出一个定义相同语言的正则表达式。作为一种可接受的证明方法,任何算法都必须满足两个标准:它必须适用于所有可想象的转移图(TG),并且必须保证在有限时间内(有限步骤内)完成任务。仅就定理证明而言,它不一定需要是一个“好”算法(快速、占用存储空间少等),只需在所有情况下都能生效即可。

This is hardly an economical start! But while the proof proper has yet to begin, a proper foundation has been laid. The proof itself will occupy twelve or so pages (with many illustrations). But my students read it with enthusiasm. I often get reports that they have stayed up half the night reading it and running hand simulations of the algorithm. And they retain from their reading the ability to execute the algorithm on simple machines.
这个开头绝不能算简洁!但尽管正式的证明尚未开始,一个坚实的基础已经奠定。证明本身占据了大约12页篇幅(包含许多插图),但我的学生们满怀热情地阅读它——我经常听到学生报告说,他们熬夜阅读并手动模拟这个算法,并且通过阅读掌握了在简单机器上执行该算法的能力。

4. Are All Functions Computable?

4. 所有函数都是可计算的吗?

I remarked above that the name “Computability” seems to be inappropriate for the first course in computing theory. Traditionally, a high point of this course has been the demonstration of the existence of “non-computable functions.” By accepting uncritically the traditional mathematical account of these phenomena, we introduce radically non-algorithmic ideas into the heart of our curriculum.
我之前提到,“可计算性”这个名称对于计算机理论入门课程来说似乎并不合适。传统上,这门课程的重点之一是证明“不可计算函数”的存在。如果我们不加批判地接受传统数学对这些现象的解释,就会将彻底非算法化的思想引入课程核心。

Indeed, the very concept of a non-computable function is problematic. First we explain functions to students in computational terms. A function from X X X to Y Y Y takes an element of X X X as input and delivers an element of Y Y Y as output. Then, a few pages or weeks later, we turn around and announce to the students that, in fact, almost all functions are non-computable! But what is a non-computable function? If a function does not correspond to an algorithm, what can it be? There is in this context no higher court corresponding to the set theory of logical mathematics. Indeed, one thing we can say is that, for our students, the term non-computable function is an oxymoron which undermines their algorithmic understanding of functions.¹ Since there are evident advantages of simplicity and unity in defining functions in terms of algorithms, we shall take the stand that functions are, by definition, computable, and then test those phenomena which are standardly taken as evidence for the existence of non-computable functions, to see if we need to yield any ground. Our strategy will be the following. Given a putative function f f f we do not ask “Is f f f computable?” but rather “What are the proper data types for the domain and range of f f f?” The latter question may have more than one natural answer, and we can consider both restricted and expanded domain/range pairs. Only if you attempt to pair an expanded domain for f f f with a restricted range will you come to the conclusion that f f f is “non-computable.”
事实上,“不可计算函数”这一概念本身就存在问题。首先,我们以计算的术语向学生解释函数:从 X X X Y Y Y 的函数将 X X X 中的元素作为输入,输出 Y Y Y 中的元素。然后,几页内容或几周课程之后,我们却转而告诉学生,事实上几乎所有函数都是不可计算的!但不可计算函数究竟是什么?如果一个函数不对应任何算法,它又能是什么?在这一背景下,不存在类似于数理逻辑集合论的“更高权威”来定义它。事实上,我们可以说,对于学生而言,“不可计算函数”这一术语本身就是矛盾的,它破坏了学生对函数的算法化理解¹。由于以算法定义函数具有明显的简洁性和统一性优势,我们将采取这样的立场:函数本质上是可计算的。然后,我们将检验那些通常被视为“不可计算函数存在”的证据的现象,看看是否需要改变这一立场。我们的策略如下:对于一个给定的假定函数 f f f,我们不追问“ f f f 是可计算的吗?”,而是追问“ f f f 的定义域和值域的适当数据类型是什么?”后一个问题可能有多个自然答案,我们可以考虑受限和扩展的定义域/值域组合。只有当你试图将 f f f 的扩展定义域与受限值域配对时,才会得出 f f f 是“不可计算的”这一结论。

¹Following Umberto Eco we might imagine a College of Oxymoronics in which a course in Non-Computable Functions would take its place in the curriculum along side such offerings as Tradition in Revolution, Democratic Oligarchy, Parménidean Dynamics, Heracliean Statics, Boolean Eristic, and Tautological Dialectics [14].

¹效仿翁贝托·埃科的思路,我们可以设想一所“矛盾修辞学院”,其课程表中会开设“不可计算函数”这一课程,与之并列的课程还包括《革命中的传统》《民主寡头制》《巴门尼德式动力学》《赫拉克利特式静力学》《布尔式争论术》以及《重言式辩证法》[14]。

The usual argument given for the existence of non-computable functions involves Cantor’s diagonal algorithm. Let us look at a typical example of how this argument is usually presented. As we will see, it is, from an algorithmic standpoint, badly flawed. I chose the following excerpt from a review by Ian Stewart not because it is unusual, but because it states the received view so well [27]:
证明不可计算函数存在的常用论证涉及康托尔对角线算法。让我们来看一个该论证的典型呈现方式——从算法角度来看,它存在严重缺陷。以下摘录自伊恩·斯图尔特(Ian Stewart)的一篇评论[27],我选择它并非因为其特殊,而是因为它很好地阐述了普遍接受的观点:

A real number is computable if its binary expansion can be the output of a computer program. It is a theorem–at first sight surprising, but true, and even easy–that “almost all” real numbers are not computable. For example, Turing used an argument that goes back to Georg Cantor to prove the existence of at least one non-computable real number.
一个实数是可计算的,当且仅当其二进制展开式可以作为计算机程序的输出。有一个定理——初看令人惊讶,但确实成立,甚至相当简单——即“几乎所有”实数都是不可计算的。例如,图灵就使用了一个可追溯至格奥尔格·康托尔(Georg Cantor)的论证,证明了至少存在一个不可计算实数。

The proof is based on the idea that all possible computer programs, each of which must be represented by a finite sequence of digits, can be listed in order. To do this, interpret the program’s defining sequence as a whole number, expressed in binary, and arrange these numbers in increasing numerical order. Now assign to each program in this list its output data, a real number expressed in binary. Run down the diagonal of this table of numbers, changing the nth digit in the nth number. The new diagonal is a number that is not on the list, which therefore corresponds to the output of no computer program whatsoever.
该证明基于这样一种思想:所有可能的计算机程序(每个程序都必须表示为有限数字序列)都可以按顺序列出。具体来说,将每个程序的定义序列解释为一个二进制整数,然后按数值递增顺序排列这些整数。接着,为列表中的每个程序分配其输出数据——一个二进制表示的实数。沿着这个数字表格的对角线移动,改变第 n n n 个数字的第 n n n 位。这个新的对角线数字不在列表中,因此它不对应任何计算机程序的输出。

Note that Stewart expresses himself in a rather algorithmic fashion, using words which imply feasible actions, like arrange, assign, run down, and change. But in fact what is proposed is completely non-algorithmic. We can indeed arrange all possible computer programs producing binary sequences in an infinite list (more precisely, we can write a program which will generate as much of this list as desired), but these programs will be partial functions which may produce a binary sequence but may, at some of the places in the sequence, compute forever without producing a 0 or a 1. We cannot change the value in such a case because there is no value to change. But we cannot be sure that there is no value, because perhaps a value will be found if we just let the program run for a longer time. The undecidability of the halting problem bars the way.
请注意,斯图尔特使用了相当算法化的表述,使用了诸如“排列”(arrange)、“分配”(assign)、“沿着……移动”(run down)和“改变”(change)等暗示可行操作的词语。但事实上,他所描述的过程完全是非算法化的。我们确实可以将所有产生二进制序列的可能计算机程序排列成一个无限列表(更精确地说,我们可以编写一个程序,生成这个列表的任意有限部分),但这些程序对应的是部分函数——它们可能产生二进制序列,但在序列的某些位置,可能会无限计算而不输出0或1。在这种情况下,我们无法改变该位置的值,因为根本没有可改变的值;但我们也无法确定该位置是否真的没有值,因为或许只要让程序运行更长时间,就会得到一个值。停机问题的不可判定性阻碍了这一过程。

But perhaps Stewart means only that we should arrange in a list only those programs which correspond to total functions. Then the diagonal algorithm will work without a hitch, but a problem remains: without an oracle we have no way of extracting from the list of all programs those which correspond to total functions, and hence cannot arrange the latter in a list. Again the halting problem halts our progress.
但或许斯图尔特的意思是,我们只需将那些对应全函数的程序列入列表。这样一来,对角线算法就能顺利运行,但另一个问题出现了:没有预言机(oracle)的帮助,我们无法从所有程序的列表中筛选出对应全函数的程序,因此无法将它们排列成列表。停机问题再次阻碍了我们的进展。

The pioneering researches of Turing, Church, and others showed that the functions defined by Turing machines (or equivalent formalisms) are typically partial, and their domains are typically undecidable (because of the undecidability of the halting problem). They also concluded that functions are typically non-computable, on the grounds that Turing machines can be enumerated, while functions cannot. Later, specific examples of non-computable functions were found, most notably the busy beaver function. We will present another interpretation of the busy beaver phenomenon, based on careful attention to the data types of domain and range, in which the busy beaver function is indeed computable. Then we will consider the Cantor diagonal algorithm and questions of cardinality.
图灵、丘奇(Church)等人的开创性研究表明,图灵机(或等价形式化方法)定义的函数通常是部分函数,其定义域通常是不可判定的(由于停机问题的不可判定性)。他们还得出结论:函数通常是不可计算的,依据是图灵机可以被枚举,而函数不能。后来,人们发现了不可计算函数的具体例子,其中最著名的是忙碌的海狸函数(busy beaver function)。我们将基于对定义域和值域数据类型的细致分析,给出对忙碌的海狸现象的另一种解释——在这种解释中,忙碌的海狸函数实际上是可计算的。之后,我们将讨论康托尔对角线算法和基数问题。

Note that I use the simple and intuitive terms decidable and enumerable instead of the more traditional “recursive” and “recursively enumerable.” A set of integers is decidable if there is an algorithm or Turing machine for deciding membership, and enumerable if there is an algorithm or Turing machine for listing its members.
请注意,我使用简单直观的“可判定的”(decidable)和“可枚举的”(enumerable)这两个术语,而非更传统的“递归的”(recursive)和“递归可枚举的”(recursively enumerable)。一个整数集合是可判定的,当且仅当存在一个算法或图灵机来判定元素是否属于该集合;是可枚举的,当且仅当存在一个算法或图灵机来列出其所有元素。

5. The Busy Beaver Function

5. 忙碌的海狸函数

The busy beaver phenomenon concerns Turing machines (TMs) whose tape alphabet consists of a single non-blank symbol, say "". A beaver is a TM which, when started on a blank tape, halts and computes an integer, known as its productivity. Several conventions are commonly used for what counts as the computation of an integer. The most restrictive requires that the machine halt on the leftmost * of a contiguous block on an otherwise blank tape. The less restrictive require only that the machine halt and take as productivity either the number of 's on the tape, the number of steps of the computation, or some other measure of the complexity of the computation. A k-state beaver is busy if, among all TMs with k states, it has greatest productivity. It does not matter which convention is taken, beavers turn out to be extremely busy. Already Rado had proved the following [26]:
忙碌的海狸现象涉及这样一类图灵机(TM):其纸带字母表仅包含一个非空白符号(例如“
”)。“海狸”(beaver)是指这样一种图灵机:它从空白纸带开始运行,最终停机并计算出一个整数,该整数被称为其“产出率”(productivity)。关于如何定义“计算一个整数”,存在多种常见约定:最严格的约定要求机器停机时,纸带仅包含一个连续的“
”块,且停机位置在该块的最左侧;较宽松的约定则仅要求机器停机,并将纸带上“*”的数量、计算步骤数或其他衡量计算复杂度的指标作为产出率。一个k状态海狸被称为“忙碌的”(busy),当且仅当在所有k状态图灵机中,它的产出率最高。无论采用哪种约定,海狸的产出率都极高。拉多(Rado)早已证明了以下定理[26]:

Rado’s Theorem: Let f f f be any (total) Turing-computable function. Then there is an integer n n n such that for all integers k ≥ n k \geq n kn there is a k-state beaver with productivity greater than f ( k ) f(k) f(k).
拉多定理:设 f f f 为任意(全)图灵可计算函数,则存在整数 n n n,使得对于所有 k ≥ n k \geq n kn,存在一个k状态忙碌的海狸,其产出率大于 f ( k ) f(k) f(k)

An extremely careful proof is given in Chapter 4 of the text [7]. If we define the busy beaver function b b bb bb by taking b b ( k ) bb(k) bb(k) to be the maximum productivity of any k-state beaver, then the theorem shows that b b bb bb grows faster than any Turing-computable function. Hence, under the Church-Turing Thesis, it might appear that b b bb bb is a non-computable function.
教材[7]的第4章给出了一个极为严谨的证明。如果我们将忙碌的海狸函数 b b bb bb 定义为: b b ( k ) bb(k) bb(k) 是所有k状态海狸的最大产出率,那么该定理表明 b b bb bb 的增长速度超过任何图灵可计算函数。因此,根据丘奇-图灵论题, b b bb bb 似乎是一个不可计算函数。

But Rado’s Theorem gives no hint of the extraordinary complexity of computations performed by extremely small machines. While k-state busy beavers have been found for k ≤ 4 k \leq 4 k4, computer searches are continually finding busier and busier 5-state beavers. Recently a 5-state machine which halts with 4,098 symbols on the tape after running for 23,554,760 steps has been announced! Note that these are 5-tuple machines, which simultaneously print and move. Other authors, like [7], work with 4-tuple machines which can either move or print (but not both at once). A 5-tuple machine with 5 states will generally convert to a 4-tuple machine with 8 or 9 states. For further discussion of busy beavers, we particularly recommend Brady’s fascinating article [8] and the entertaining account in the Scientific American column of Dewdney [13].
但拉多定理并未揭示极小状态机器所执行的计算的极端复杂性。虽然对于 k ≤ 4 k \leq 4 k4,k状态忙碌的海狸已经被找到,但计算机搜索仍在不断发现产出率更高的5状态海狸。最近有报道称,一个5状态图灵机在运行23,554,760步后停机,纸带上留下了4,098个符号!请注意,这些是5元组图灵机(同时执行打印和移动操作);而其他学者(如[7])使用的是4元组图灵机(只能执行移动或打印操作,不能同时进行)。一个5状态5元组图灵机通常可以转换为一个8或9状态的4元组图灵机。关于忙碌的海狸的进一步讨论,我们特别推荐布雷迪(Brady)引人入胜的文章[8]和杜德尼(Dewdney)在《科学美国人》专栏中的趣味报道[13]。

The busy beaver function b b bb bb becomes computable when its domain and range are properly defined. When the domain is taken to be N \mathbb{N} N, the range will be the set of “weak integers,” a superset of N \mathbb{N} N which we shall define shortly. Rado’s Theorem then demonstrates that b b bb bb grows faster than any integer-valued function.
当忙碌的海狸函数 b b bb bb 的定义域和值域被适当定义时,它就变成了可计算函数。当定义域为自然数集 N \mathbb{N} N 时,其值域将是“弱整数”(weak integers)集——这是 N \mathbb{N} N 的一个超集,我们将在下文定义。此时,拉多定理表明 b b bb bb 的增长速度超过任何整数值函数。

To determine the proper data type for b b ( k ) bb(k) bb(k), simply attempt to compute it by brute force. First list all k-state machines (the number of such machines is staggeringly large, so this is, of course, feasible only for very small k k k). Then run all of the k-state machines in parallel. Whenever one of them halts, determine its productivity and include it in the output. We obtain an enumerable set of integers, of cardinality bounded by the (very large) number of k-state TMs. But the process of generating this enumerable set will not halt, even though the set has bounded cardinality. Many of the TMs will never halt, and while we can weed out many obvious non-halters, there will be others whose status we will be unable to decide, so we will have to keep them running. We are led to the following definition.
要确定 b b ( k ) bb(k) bb(k) 的适当数据类型,只需尝试通过蛮力法计算它:首先列出所有k状态图灵机(这类机器的数量极其庞大,因此这仅对非常小的 k k k 可行);然后并行运行所有这些k状态图灵机;每当其中一个机器停机时,计算其产出率并将其纳入输出。我们得到的是一个可枚举的整数集,其基数受限于k状态图灵机的数量(非常大)。但尽管该集合的基数是有界的,生成这个可枚举集的过程却永远不会停止——因为许多图灵机永远不会停机,而且虽然我们可以剔除许多明显不会停机的机器,但仍有一些机器的停机状态无法判定,因此必须让它们继续运行。这引出了以下定义:

Definition: A weak integer X X X is an enumerable set of positive integers which contains at least one and at most B B B elements, for some integer B B B.
定义:弱整数 X X X 是一个可枚举的正整数集,存在整数 B B B,使得 X X X 包含至少1个且至多 B B B 个元素。

Intuitively, a weak integer X X X represents an approximation from below, and every element x ∈ X x \in X xX establishes a lower bound. It is crucial to understand that while we are given a bound B B B on the number of elements in a weak integer X X X, we do not necessarily have any bound on the values of these elements. For we do not generally have access to the entire list, but only to the algorithm or TM which enumerates it. So, in concrete terms, a weak integer is an algorithm or Turing machine which enumerates a set of integers of bounded cardinality. Given k k k, the function b b bb bb produces such a TM b b ( k ) bb(k) bb(k) by the finite process outlined above.
直观地说,弱整数 X X X 表示一个从下方逼近的数值,其中每个元素 x ∈ X x \in X xX 都是一个下界。关键在于,虽然我们知道弱整数 X X X 中元素的数量有界( B B B),但这些元素的值本身不一定有界——因为我们通常无法获取整个元素列表,只能获取枚举该列表的算法或图灵机。因此,具体而言,弱整数是一个枚举有界基数整数集的算法或图灵机。对于给定的 k k k,函数 b b bb bb 通过上述有限过程生成这样一个图灵机 b b ( k ) bb(k) bb(k)

The situation here is analogous to that of real numbers. When we speak of a real number x x x we generally have in mind a Cauchy sequence of rationals. But when an algorithm produces a real number x x x which is not rational, what it actually delivers as x x x is an algorithm for computing as much of the Cauchy sequence as we may wish to see [20]. Similarly, when we speak of a weak integer X X X, we have in mind an enumerable set of integers. But when an algorithm produces a weak integer which is not an integer, what it actually delivers is an algorithm or Turing machine for enumerating as much of that set as we may wish to see.
这种情况与实数的情况类似:当我们谈论一个实数 x x x 时,通常想到的是一个有理数柯西序列;但当一个算法生成一个无理数 x x x 时,它实际输出的是一个算法——该算法可以计算出这个柯西序列的任意有限部分[20]。同样,当我们谈论一个弱整数 X X X 时,想到的是一个可枚举的整数集;但当一个算法生成一个非整数的弱整数时,它实际输出的是一个算法或图灵机——该算法可以枚举这个集合的任意有限部分。

Keeping in mind that weak integers approximate from below, it is natural to define equality and order on the collection of all weak integers as follows. For weak integers X X X and Y Y Y:
考虑到弱整数是从下方逼近的,我们可以自然地定义所有弱整数上的相等和序关系如下(对于弱整数 X X X Y Y Y):

  • X ≤ Y X \leq Y XY means ( ∀ x ∈ X ) ( ∃ y ∈ Y ) ( x ≤ y ) (\forall x \in X)(\exists y \in Y)(x \leq y) (xX)(yY)(xy)

  • X ≤ Y X \leq Y XY 表示:对于所有 x ∈ X x \in X xX,存在 y ∈ Y y \in Y yY,使得 x ≤ y x \leq y xy

  • X = Y X = Y X=Y means ( X ≤ Y ) ∧ ( Y ≤ X ) (X \leq Y) \land (Y \leq X) (XY)(YX)

  • X = Y X = Y X=Y 表示: X ≤ Y X \leq Y XY Y ≤ X Y \leq X YX

  • X < Y X < Y X<Y means ( ∃ y ∈ Y ) ( ∀ x ∈ X ) ( x < y ) (\exists y \in Y)(\forall x \in X)(x < y) (yY)(xX)(x<y)

    X < Y X < Y X<Y 表示:存在 y ∈ Y y \in Y yY,使得对于所有 x ∈ X x \in X xX,都有 x < y x < y x<y

By associating each integer n n n with the singleton set { n } \{n\} {n}, the integers become a subset of the weak integers. Clearly a weak integer X X X equals an integer x x x if and only if x x x is the maximum element of X X X.
通过将每个整数 n n n 与单元素集 { n } \{n\} {n} 关联,整数集成为弱整数集的一个子集。显然,一个弱整数 X X X 等于一个整数 x x x,当且仅当 x x x X X X 的最大元素。

Hence there are really two busy beaver functions. Rather than extend the range to the set of weak integers, we could shrink the domain to D D D, the set of integers at which b b bb bb takes integer values ( D D D contains at least { 1 , . . . , 4 } \{1, ..., 4\} {1,...,4} ).
因此,实际上存在两个忙碌的海狸函数:除了将值域扩展到弱整数集,我们也可以将定义域缩小到 D D D——即 b b bb bb 取整数值的整数集( D D D 至少包含 { 1 , . . . , 4 } \{1, ..., 4\} {1,...,4})。

We can now deduce from Rado’s Theorem:
基于拉多定理,我们可以得出:

The Busy Beaver Theorem: Let f f f be any total Turing-computable function from N \mathbb{N} N to N \mathbb{N} N. Then there is an integer n n n such that b b ( k ) > f ( k ) bb(k) > f(k) bb(k)>f(k) for all k ≥ n k \geq n kn. That is, the busy beaver function grows faster than any total integer-valued function.
忙碌的海狸定理:设 f f f 为任意从 N \mathbb{N} N N \mathbb{N} N 的全图灵可计算函数,则存在整数 n n n,使得对于所有 k ≥ n k \geq n kn,有 b b ( k ) > f ( k ) bb(k) > f(k) bb(k)>f(k)。即,忙碌的海狸函数的增长速度超过任何全整数值函数。

This theorem confirms our intuition that the complexity of a computation is incomparably more sensitively linked to the size of the machine than to the size of the input. There can be no universal total machine which computes all (total) functions from N \mathbb{N} N to N \mathbb{N} N; no single machine can keep up with a sequence of ever larger machines. Note that, since we do have a universal machine for partial functions, this implies the unsolvability of the halting problem, for if we could decide the halting problem then we could carry out a brute force computation of b b ( k ) bb(k) bb(k) as an integer by running all machines with k states which halt when started on a blank tape.
该定理证实了我们的直觉:计算的复杂性与机器大小的关联,远比与输入大小的关联更为敏感。不存在能计算所有从 N \mathbb{N} N N \mathbb{N} N 的全函数的通用全机器——没有任何单个机器能跟上一系列越来越大的机器的计算能力。请注意,由于我们确实有用于部分函数的通用机器,这意味着停机问题是不可解的——因为如果我们能判定停机问题,就可以通过运行所有从空白纸带开始并停机的k状态机器,以蛮力法计算出作为整数的 b b ( k ) bb(k) bb(k)

The theorem also shows that we can obtain faster growing functions by relaxing the data type of the range. Functions to the weak integers can grow faster than functions to the integers. Hence the weak integers cannot be identified with the integers, and this interpretation requires that we use intuitionistic rather than classical logic. Using classical logic, it can be shown that every set of integers of bounded cardinality contains a greatest element, and hence every weak integer equals an integer. The weak integers form an intuitionistic extension of N \mathbb{N} N [28].
该定理还表明,通过放宽值域的数据类型,我们可以得到增长速度更快的函数:取值为弱整数的函数可以比取值为整数的函数增长得更快。因此,弱整数不能等同于整数,这一解释要求我们使用直觉主义逻辑而非经典逻辑。在经典逻辑中,可以证明每个有界基数的整数集都包含一个最大元素,因此每个弱整数都等于一个整数。而弱整数构成了 N \mathbb{N} N 的一个直觉主义扩展[28]。

6. The Diagonal Algorithm

6. 对角线算法

We shall consider the Cantor diagonal method (which we will call the diagonal algorithm) in the context of the set N N \mathbb{N}^\mathbb{N} NN of all integer-valued functions. The algorithm takes as input a sequence of such functions { F k ( n ) } \{F_k(n)\} {Fk(n)} and produces as output a function G G G different from each F k F_k Fk. It was Cantor’s genius to notice that this is achieved if we simply “go down the diagonal” and construct G G G by a simple rule such as G ( n ) = F n ( n ) + 1 G(n) = F_n(n) + 1 G(n)=Fn(n)+1.
我们将在所有整数值函数的集合 N N \mathbb{N}^\mathbb{N} NN 的背景下讨论康托尔对角线法(我们称之为对角线算法)。该算法以一个此类函数序列 { F k ( n ) } \{F_k(n)\} {Fk(n)} 为输入,输出一个与每个 F k F_k Fk 都不同的函数 G G G。康托尔的天才之处在于发现:只需“沿着对角线”,通过简单规则(如 G ( n ) = F n ( n ) + 1 G(n) = F_n(n) + 1 G(n)=Fn(n)+1)构造 G G G,即可实现这一目标。

As long as the functions F k F_k Fk are total, this procedure is wholly algorithmic, and the implication is similar to one drawn from busy beavers: there does not exist a universal total machine. A single fixed Turing machine which takes two integer inputs k k k and n n n cannot, by fixing one input, imitate the behavior of an arbitrary machine which takes one integer input, when all functions are required to be total (which is hardly surprising, since Cantor also showed that two integers are really no better than one).
只要函数 F k F_k Fk 是全函数,该过程就是完全算法化的,其蕴含的结论与忙碌的海狸函数的结论类似:不存在通用全机器。当所有函数都要求是全函数时,一个固定的、接受两个整数输入 k k k n n n 的图灵机,无法通过固定其中一个输入来模拟任意接受一个整数输入的机器的行为(这并不奇怪,因为康托尔也证明了两个整数并不比一个整数更具优势)。

The diagonal algorithm is commonly used to point to the existence of non-computable functions in two different ways. It is used to directly construct specific non-computable functions as in the argument of Stewart given above. Used indirectly, it is the source of the theory of infinite cardinal numbers, which seems to imply that almost all functions are non-computable. The direct construction of a non-computable function by the diagonal algorithm is carried out with great care in Chapter 5 of [7]. The basic idea is very simple. The collection of all Turing machines which compute partial functions is arranged in a list { F k } \{F_k\} {Fk} so that F k ( n ) F_k(n) Fk(n) represents the value computed by the k-th TM when given input n n n. Note that while we have a list of all Turing machines which compute partial functions, we have no way of extracting the list of those machines which compute total functions, because of the undecidability of the halting problem. Because the functions are partial, we must modify the diagonal algorithm:
对角线算法通常以两种方式被用来证明不可计算函数的存在:一种是直接构造特定的不可计算函数(如上述斯图尔特的论证);另一种是间接用于无穷基数理论的构建,该理论似乎暗示几乎所有函数都是不可计算的。教材[7]的第5章详细阐述了如何通过对角线算法直接构造不可计算函数,其基本思想非常简单:将所有计算部分函数的图灵机排列成一个列表 { F k } \{F_k\} {Fk},其中 F k ( n ) F_k(n) Fk(n) 表示第k个图灵机在输入 n n n 时计算出的值。请注意,虽然我们可以列出所有计算部分函数的图灵机,但由于停机问题的不可判定性,我们无法从中筛选出计算全函数的图灵机。由于这些函数是部分函数,我们必须修改对角线算法:

G ( n ) = { 1 if  F n ( n )  is undefined F n ( n ) + 1 otherwise G(n) = \begin{cases} 1 & \text{if } F_n(n) \text{ is undefined} \\ F_n(n) + 1 & \text{otherwise} \end{cases} G(n)={1Fn(n)+1if Fn(n) is undefinedotherwise

Certainly G G G is a total function which is distinct from every Turing computable function, and it is very tempting to say that G ( n ) G(n) G(n) is an integer, since it is an integer if F n ( n ) F_n(n) Fn(n) is defined or is undefined. Using classical logic, we could conclude that logically G ( n ) G(n) G(n) must be an integer. On the other hand, it is certainly not an integer in any computational sense, since we have no general way of finding its value. (Indeed, here lurks another proof of the undecidability of the halting problem). So the question arises, what is the data type of G ( n ) G(n) G(n)? Again, we must describe the proper superset of N \mathbb{N} N. (Warning: this definition will seem artificial and even paradoxical to those unused to intuitionistic logic. But the artificiality really resides in the application of the diagonal algorithm to a sequence of partial functions.)
显然, G G G 是一个全函数,且与每个图灵可计算函数都不同。由于无论 F n ( n ) F_n(n) Fn(n) 是定义的还是未定义的, G ( n ) G(n) G(n) 都是一个整数,因此我们很容易认为 G ( n ) G(n) G(n) 是一个整数。在经典逻辑中,我们可以得出结论:从逻辑上讲, G ( n ) G(n) G(n) 必定是一个整数。但另一方面,从计算意义上讲, G ( n ) G(n) G(n) 显然不是一个整数——因为我们没有通用方法来计算它的值(事实上,这隐含了停机问题不可判定性的另一个证明)。因此,问题出现了: G ( n ) G(n) G(n) 的数据类型是什么?我们再次需要描述 N \mathbb{N} N 的一个适当超集。(警告:对于不熟悉直觉主义逻辑的人来说,这个定义会显得人为且甚至矛盾,但这种人为性实际上源于将对角线算法应用于部分函数序列。)

Definition: A singleton integer is a set X X X of integers satisfying:
定义:单元素整数(singleton integer)是一个满足以下条件的整数集 X X X

  • X X X contains at most one integer (i.e. if x ∈ X x \in X xX and y ∈ X y \in X yX, then x = y x = y x=y),
    X X X 包含至多一个整数(即,如果 x ∈ X x \in X xX y ∈ X y \in X yX,则 x = y x = y x=y);
  • X X X is non-empty (in the sense that it is contradictory that X = ∅ X = \emptyset X=).
    X X X 是非空的(即, X = ∅ X = \emptyset X= 是矛盾的)。

A similar definition is found in [11].
类似的定义可见于[11]。

The function G G G, defined above by the diagonal algorithm, is a (computable) function from N \mathbb{N} N to the set of singleton integers. If we identify each integer m m m with the singleton set { m } \{m\} {m}, then the singleton integers become an (intuitionistic) extension of N \mathbb{N} N. If we require G G G to take integer values, then the domain must be restricted to the set of integers n n n for which F n ( n ) F_n(n) Fn(n) is either defined or undefined. This subset, while it has empty complement, cannot be identified with N \mathbb{N} N (again a paradoxical situation for those unused to the algorithmic niceties of intuitionistic logic). We should emphasize that, unlike weak integers, singleton integers are not in general enumerable. Indeed, an enumerable singleton integer is very close to being an ordinary integer and can be proved equal to an ordinary integer if Markov’s principle is assumed (see [5], p. 63). While Markov’s principle is often considered constructive or very weakly non-constructive, it has the effect of erasing the algorithmically significant distinction between algorithms which are merely known not to run forever and those for which there exists an upper bound on runtime.
上述通过对角线算法定义的函数 G G G 是一个从 N \mathbb{N} N 到单元素整数集的(可计算)函数。如果我们将每个整数 m m m 与单元素集 { m } \{m\} {m} 关联,那么单元素整数集就成为 N \mathbb{N} N 的一个(直觉主义)扩展。如果要求 G G G 取整数值,则定义域必须限制为这样的整数 n n n F n ( n ) F_n(n) Fn(n) 要么是定义的,要么是未定义的。这个子集虽然补集为空,但不能等同于 N \mathbb{N} N(对于不熟悉直觉主义逻辑算法精妙之处的人来说,这又是一个矛盾的情况)。我们需要强调的是,与弱整数不同,单元素整数通常是不可枚举的。事实上,一个可枚举的单元素整数非常接近普通整数,并且如果假设马尔可夫原理(Markov’s principle)成立,它可以被证明等于一个普通整数(见[5],第63页)。尽管马尔可夫原理通常被认为是构造性的或极弱的非构造性的,但它的作用是消除了“已知不会永远运行的算法”与“运行时间存在上界的算法”之间在算法意义上的重要区别。

It is often felt that the existence of non-computable functions shows that mathematics necessarily transcends the algorithmic. I have tried to show that this is not so, that the phenomena standardly connected with non-computability can better be understood in purely algorithmic terms. The usual approach simply lumps together the busy beaver function and the function output by the diagonal algorithm as “non-computable functions.” Our approach distinguishes them in terms of the very different data types of their natural ranges.
人们常常认为,不可计算函数的存在表明数学必然超越算法。但我试图说明的是,情况并非如此——那些通常与不可计算性相关的现象,可以通过纯算法术语得到更好的理解。传统方法简单地将忙碌的海狸函数和对角线算法输出的函数归为“不可计算函数”,而我们的方法则根据它们自然值域的截然不同的数据类型来区分它们。

7. Cardinality as shape

7. 作为形状的基数

Cantor argued that the diagonal algorithm showed that the set N N \mathbb{N}^\mathbb{N} NN contained more elements than the set N \mathbb{N} N of natural numbers. It is this last step which introduces into mathematics a supposed universe of non-algorithmic functions. We might well wonder how so simple an algorithm could transcend the computable.² Cantor did indeed show that there is a fundamental difference between the sets N N \mathbb{N}^\mathbb{N} NN and N \mathbb{N} N, but this difference can be understood not as a quantitative difference, but as a difference of quality or structure. Rather than call the set N N \mathbb{N}^\mathbb{N} NN uncountable, it might better be called productive, because there are very powerful methods for producing elements of N N \mathbb{N}^\mathbb{N} NN, in particular for producing an element outside of any given sequence in N N \mathbb{N}^\mathbb{N} NN [16].
康托尔认为,对角线算法表明集合 N N \mathbb{N}^\mathbb{N} NN 包含的元素比自然数集 N \mathbb{N} N 更多。正是这最后一步,将一个所谓的“非算法函数宇宙”引入了数学。我们不禁要问,如此简单的一个算法,怎么会超越可计算的范畴?² 康托尔确实证明了 N N \mathbb{N}^\mathbb{N} NN N \mathbb{N} N 之间存在根本差异,但这种差异不应被理解为数量差异,而应是性质或结构差异。与其称 N N \mathbb{N}^\mathbb{N} NN 为“不可数集”,不如称其为“能产集”(productive set)——因为存在非常强大的方法来生成 N N \mathbb{N}^\mathbb{N} NN 的元素,尤其是生成任何给定 N N \mathbb{N}^\mathbb{N} NN 序列之外的元素[16]。

²This point was perhaps first made by Wittgenstein, who wrote of the diagonal algorithm: “Our suspicion ought always to be aroused when a proof proves more than its means allow it. Something of this sort might be called a ‘puffed-up proof’.” ([29], p. 56)

²这一观点或许最早由维特根斯坦提出,他在谈及对角线算法时写道:“当一个证明得出的结论超出了其手段所能支撑的范围时,我们应始终对此抱有怀疑。这类证明或许可以被称作‘膨胀的证明’。”([29],第 56 页)

Definition: A set X X X is productive if, for every function f : N → X f: \mathbb{N} \to X f:NX, there exists an x ∈ X x \in X xX outside of f ( N ) f(\mathbb{N}) f(N).
定义:一个集合 X X X 是能产集,当且仅当对于每个函数 f : N → X f: \mathbb{N} \to X f:NX,存在 x ∈ X x \in X xX x ∉ f ( N ) x \notin f(\mathbb{N}) x/f(N)

Cantor’s Theorem: The set N N \mathbb{N}^\mathbb{N} NN is productive.
康托尔定理:集合 N N \mathbb{N}^\mathbb{N} NN 是能产集。

This use of the term productive, taken from recursive function theory, grounds our understanding in algorithmic reality rather than idealistic fantasy.³ Given any sequence of elements of N N \mathbb{N}^\mathbb{N} NN, we can find an element of N N \mathbb{N}^\mathbb{N} NN outside the sequence, not because there are more functions than integers, but because of the structure of N N \mathbb{N}^\mathbb{N} NN.
“能产集”这一术语源自递归函数理论,它使我们的理解立足于算法现实,而非唯心主义空想³。给定任何 N N \mathbb{N}^\mathbb{N} NN 的元素序列,我们都能找到该序列之外的 N N \mathbb{N}^\mathbb{N} NN 元素——这并非因为函数的数量多于整数,而是因为 N N \mathbb{N}^\mathbb{N} NN 的结构本身具有这样的性质。

³The fantasy here is not the theory of sets, as elegantly elaborated in the concrete confines of Zermelo-Fraenkel set theory, but rather the notion that, somewhere, there are really “more” elements of N N \mathbb{N}^\mathbb{N} NN than of N \mathbb{N} N. It is worth remembering that Cantor lobbied the Vatican to recognize that the higher cardinals pointed the way to God [12, 18].

³这里的“空想”并非指策梅洛-弗兰克尔集合论在具体框架下优雅构建的集合理论,而是那种认为在某种意义上 N N \mathbb{N}^\mathbb{N} NN 的元素真的“多于” N \mathbb{N} N 元素的观念。值得一提的是,康托尔曾游说梵蒂冈,希望其承认更高阶的基数指向了通往上帝的道路 [12, 18]。

Of course it follows from the diagonal algorithm that there is no surjection from N \mathbb{N} N to N N \mathbb{N}^\mathbb{N} NN. Let N p a r N \mathbb{N}^\mathbb{N}_{par} NparN denote the set of all partial binary functions on N \mathbb{N} N, with intensional equality. Then, under the assumptions of the Church-Turing Thesis, the set of all partial functions can be represented by the set of Turing machines, which can be listed, so there is indeed a bijection from N \mathbb{N} N to N p a r N \mathbb{N}^\mathbb{N}_{par} NparN. Since N N \mathbb{N}^\mathbb{N} NN is a subset of N p a r N \mathbb{N}^\mathbb{N}_{par} NparN, this might be considered as evidence that N \mathbb{N} N is larger than N N \mathbb{N}^\mathbb{N} NN, were one inclined to make a quantitative comparison between them. Cantor, and most mathematicians after him, considered sets as “mere collections of elements,” which could differ only in quantity. We do not find this position algorithmically intelligible, since the extra structure of N N \mathbb{N}^\mathbb{N} NN plays an essential role in the diagonal algorithm.
显然,由对角线算法可推出,不存在从 N \mathbb{N} N N N \mathbb{N}^\mathbb{N} NN 的满射。设 N p a r N \mathbb{N}^\mathbb{N}_{par} NparN 表示 N \mathbb{N} N 上所有部分二元函数的集合(采用内涵相等)。根据丘奇-图灵论题,所有部分函数的集合可以由图灵机集合表示,而图灵机可以被枚举,因此存在从 N \mathbb{N} N N p a r N \mathbb{N}^\mathbb{N}_{par} NparN 的双射。由于 N N \mathbb{N}^\mathbb{N} NN N p a r N \mathbb{N}^\mathbb{N}_{par} NparN 的子集,若有人倾向于对它们进行数量比较,这或许可以被视为 N \mathbb{N} N N N \mathbb{N}^\mathbb{N} NN “更大”的证据。康托尔及其之后的大多数数学家将集合视为“纯粹的元素集合”,认为集合之间的差异仅在于数量。但我们认为这一立场在算法意义上是不可理解的——因为 N N \mathbb{N}^\mathbb{N} NN 的额外结构在对角线算法中起到了至关重要的作用。

If we want a simple metaphor for differences such as that between N \mathbb{N} N and N N \mathbb{N}^\mathbb{N} NN, shape might be better than size. It is then perfectly intelligible to maintain that N ⊂ N N ⊂ N p a r N \mathbb{N} \subset \mathbb{N}^\mathbb{N} \subset \mathbb{N}^\mathbb{N}_{par} NNNNparN, where N \mathbb{N} N and N p a r N \mathbb{N}^\mathbb{N}_{par} NparN have the same shape, which is distinct from that of N N \mathbb{N}^\mathbb{N} NN.
如果我们想用一个简单的隐喻来描述 N \mathbb{N} N N N \mathbb{N}^\mathbb{N} NN 这类差异,“形状”(shape)或许比“大小”(size)更合适。这样一来,我们就可以合理地认为 N ⊂ N N ⊂ N p a r N \mathbb{N} \subset \mathbb{N}^\mathbb{N} \subset \mathbb{N}^\mathbb{N}_{par} NNNNparN,其中 N \mathbb{N} N N p a r N \mathbb{N}^\mathbb{N}_{par} NparN 具有相同的“形状”,而这与 N N \mathbb{N}^\mathbb{N} NN 的“形状”截然不同。

8. Algorithmic logics

8. 算法逻辑

We have seen that if we are to take the stand that all functions are computable, we must distinguish the ordinary integers from such intuitionistic extensions as the weak integers and the singleton integers. This requires that we adopt a logic such as intuitionistic logic which allows us to make such distinctions.
我们已经看到,若要坚持“所有函数都是可计算的”这一立场,就必须区分普通整数与弱整数、单元素整数等直觉主义扩展。这要求我们采用一种能够支持此类区分的逻辑,例如直觉主义逻辑。

Brouwer claimed that the Law of Excluded Middle was not algorithmically valid and developed intuitionistic logic as a subset of classical logic. However, there is another way to view the difference between the two logics. Since intuitionistic logic allows us to make more distinctions, it must itself contain additional distinctions. Most basically, intuitionistic logic distinguishes between a statement and its double negation, and distinguishes the constructive disjunction A ∨ B A \lor B AB from the classical disjunction ¬ ( ¬ A ∧ ¬ B ) \neg(\neg A \land \neg B) ¬(¬A¬B). It is this richness of distinctions which allows the distinction between the integers and the weak integers or singleton integers.
布劳威尔(Brouwer)认为排中律在算法意义上是无效的,并将直觉主义逻辑发展为经典逻辑的一个子集。但我们还可以从另一个角度看待这两种逻辑的差异:由于直觉主义逻辑允许我们做出更多区分,它本身必然包含额外的差异维度。最基本的是,直觉主义逻辑区分一个命题与其双重否定,并区分构造性析取 A ∨ B A \lor B AB 与经典析取 ¬ ( ¬ A ∧ ¬ B ) \neg(\neg A \land \neg B) ¬(¬A¬B)。正是这种丰富的区分能力,使得我们能够区分整数与弱整数、单元素整数。

Looking at algebras rather than sets of truths, we can see classical logic as a quotient or collapsing of intuitionistic logic. From the algorithmic standpoint, classical logic does not make enough distinctions. In the logical paradigm for mathematics, the traditional test for correctness is consistency, and while this has an appealing simplicity, it turns out not to be sufficient for the needs of algorithms. As Errett Bishop forcefully stated: meaningful distinctions deserve to be maintained [6]. Similar ideas were recently expressed in [23]:
如果我们从代数而非真理集合的角度看待逻辑,经典逻辑可以被视为直觉主义逻辑的一个商代数或“坍缩”形式。从算法角度来看,经典逻辑未能做出足够的区分。在数学的逻辑范式中,正确性的传统检验标准是一致性——尽管这一标准具有吸引人的简洁性,但事实证明它无法满足算法的需求。正如埃里特·毕晓普(Errett Bishop)有力指出的:有意义的区分值得被保留[6]。文献[23]中最近也表达了类似观点:

A common misconception among mathematicians is to think of intuitionistic mathematics as “mathematics without the law of the excluded middle” (the law asserting that every statement is either true or false). From this point of view, intuitionistic mathematics is a proper subset of ordinary mathematics, and doing your mathematics intuitionistically is like doing it with your hands tied behind your back.
数学家们普遍存在一个误解,认为直觉主义数学是“没有排中律的数学”(排中律主张每个命题要么为真,要么为假)。从这一角度来看,直觉主义数学是普通数学的一个真子集,而用直觉主义方法做数学就像是双手被绑在身后做事。

Another more realistic viewpoint is to regard intuitionistic logic, and the mathematics based on that logic, as the logic of sets with some structure, rather than of bare sets. Traditional examples are sets growing in time (as in Kripke semantics), or sets with some recursive structure (as in Kleene’s realizability interpretation), or sets continuously varying over some fixed parameter space. Universes of such sets are perfectly suitable for developing mathematics, but one is often forced to use intuitionistic logic.
另一种更现实的观点是,将直觉主义逻辑及基于该逻辑的数学视为“具有某种结构的集合的逻辑”,而非“纯粹集合的逻辑”。传统的例子包括随时间增长的集合(如克里普克语义学中的集合)、具有某种递归结构的集合(如克莱尼可实现性解释中的集合),或在某个固定参数空间上连续变化的集合。这类集合构成的论域完全适合发展数学,但人们通常不得不使用直觉主义逻辑。

In the first half of this century, the interest in intuitionistic logic and mathematics was mainly of a philosophical and foundational nature. More recently, it has become apparent that intuitionistic logic or some variant thereof is often the right logic to use in theories of computing.
在本世纪上半叶,人们对直觉主义逻辑和数学的兴趣主要集中在哲学和基础层面。但近年来,越来越明显的是,直觉主义逻辑或其某种变体,往往是计算理论中合适的逻辑选择。

Of course, from an algorithmic standpoint, there can be no such thing as a “bare” set, except possibly finite sets. Any set carries a structure by virtue of its construction. The weak integers and singleton integers can be considered as further examples of sets “growing in time.”
当然,从算法角度来看,除了有限集之外,不存在所谓的“纯粹”集合——任何集合都因其构造方式而具有某种结构。弱整数和单元素整数可以被视为“随时间增长的集合”的进一步例子。

What logic should we teach our students? Traditionally, classical logic has been the only logic used. Indeed, students have often been taught that “to prove something, assume it is false and try to derive a contradiction.” From an algorithmic standpoint there could hardly be worse general advice. When intuitionistic logic has been mentioned, it has often been in the pejorative category of a “deviant logic.” But intuitionistic logic makes it natural to think of proofs as programs, and on this grounds should be preferred. We have found that some sort of natural deduction system provides an excellent way to introduce students to logic with an algorithmic flavor.
我们应该教学生哪种逻辑?传统上,经典逻辑是唯一被教授的逻辑。事实上,学生们经常被教导:“要证明一个命题,先假设它为假,然后尝试推导出矛盾。”从算法角度来看,几乎没有比这更糟糕的通用建议了。当提及直觉主义逻辑时,它往往被归为“异常逻辑”的贬义范畴。但直觉主义逻辑自然地将证明视为程序,基于这一点,它应当被优先采用。我们发现,某种形式的自然演绎系统是向学生介绍具有算法风味的逻辑的绝佳方式。

Ultimately we would, of course, like our students to be literate in both classical and intuitionistic logic. Experience has shown that those who think classically have a very difficult time understanding intuitionistic thought. The law of excluded middle is made part of one’s subconscious thought and even questioning it seems strange. On the other hand, those who start with intuitionistic logic have no difficulty in adding excluded middle when appropriate (for example for decidable propositions). This seems to me to be a very strong argument for starting with intuitionistic logic.
当然,我们最终希望学生能够同时掌握经典逻辑和直觉主义逻辑。但经验表明,习惯于经典逻辑思维的人很难理解直觉主义思想——排中律已成为他们潜意识的一部分,甚至对其提出质疑都会显得奇怪。相反,从直觉主义逻辑开始学习的人,在适当情况下(例如对于可判定命题)添加排中律毫无困难。在我看来,这是支持从直觉主义逻辑开始教学的一个非常有力的论据。

An analogous situation holds in programming languages. Ultimately, of course, programmers will want to be able to use non-local control mechanisms, but experience has shown that those who start using GOTO as novice programmers develop bad habits which are very hard to erase. This analogy between local control and intuitionistic logic and non-local control and classical logic actually runs quite deep, as shown in other papers at this symposium[24].
编程语言领域也存在类似情况。当然,程序员最终希望能够使用非局部控制机制,但经验表明,新手程序员若一开始就使用GOTO语句,会养成难以改正的坏习惯。正如本次研讨会的其他论文所展示的[24],局部控制与直觉主义逻辑、非局部控制与经典逻辑之间的类比,实际上有着非常深刻的联系。

The algorithmic spirit is diverse. We have a multitude of programming languages, programming paradigms, operating systems, etc., and this is recognized as a healthy situation in which the diversity leads to evolutionary progress (even though our students may complain about having to learn more than one programming language).
算法精神的核心是多样性。我们拥有众多编程语言、编程范式、操作系统等,这被视为一种健康的状态——多样性带来了进化性的进步(尽管学生们可能会抱怨需要学习不止一种编程语言)。

Mathematics, on the other hand, has been characterized by conformity. Physicists may still be seeking the “grand unified theory,” but mathematicians seemed to have found theirs. For the past half century adherence to Zermelo-Frankel set theory and classical logic as the foundations of mathematics has been virtually unquestioned. While this unity has some advantages, it has also led to a stifling of fresh inquiry into the nature of mathematics.
另一方面,数学的特点是一致性。物理学家或许仍在寻找“大统一理论”,但数学家们似乎已经找到了他们的“统一理论”。在过去的半个世纪里,以策梅洛-弗兰克尔集合论和经典逻辑作为数学基础的做法,几乎从未受到质疑。这种统一性虽然有其优势,但也导致了对数学本质的新探索受到压制。

Following the algorithmic spirit, we might hope that in the future mathematics will become more diverse, that students will be presented with a genuine choice among a range of foundational outlooks, and that they will learn, in particular, to view mathematics algorithmically.
遵循算法精神,我们或许可以期望,未来的数学将变得更加多样化,学生们将能够在一系列基础观点中做出真正的选择,尤其是能够学会以算法的视角看待数学。

References

参考文献

  1. Abelson, H. and Sussman, G.J. Structure and Interpretation of Computer Programs. M. I. T. Press, 1984.
  2. Bates, J. L. and Constable, R. L. “Proofs as programs”. ACM Transactions on Programming Languages and Systems 7(1985), 113-136.
  3. Beeson, M. Computerizing mathematics: logic and computation. In Herken, R., Ed., The Universal Turing Machine: a Half-Century Survey, Oxford University Press, 1988, pp. 191-225.
  4. Bishop, E. Foundations of Constructive Analysis. McGraw-Hill, 1967. [5] is a new edition.
  5. Bishop, E. and Bridges, D. Constructive Analysis. Springer-Verlag, 1985. Revised edition of [4].
  6. Bishop, E. Contemporary Mathematics. Volume 39: Schizophrenia in Contemporary Mathematics. In Rosenblatt, M., Ed., Errett Bishop: Reflections on Him and His Research, American Mathematical Society, 1985. Originally distributed as the American Mathematical Society Colloquium Lectures in 1973.
  7. Boolos, G. S., and Jeffrey, R. C. Computability and Logic. Cambridge University Press, 1980.
  8. Brady, A. H. The busy beaver game and the meaning of life. In Herken, R. Ed., The Universal Turing Machine: a Half-Century Survey, Oxford University Press, 1988, pp. 259-278.
  9. Cohen, D.I. A. Introduction to Computer Theory. John Wiley and Sons, 1986.
  10. Constable, R. L. “Programs as proofs: a synopsis”. Information Processing Letters 16 (1983),105-112.
  11. Dalen, D. van. Singleton Reals. In Logic Colloquium '80, North-Holland, 1982, pp. 83-94.
  12. Dauben, J., W. Georg Cantor: His Mathematics and Philosophy of the Infinite. Harvard University Press, 1979.
  13. Dewdney, A. K. “Computer Recreations”. Scientific American 252 (April, 1984), 20-30. Reprinted in The Armchair Universe, Freeman, 1988, 160-171.
  14. Eco, Umberto. Foucault’s Pendulum. Harcourt Brace Jovanovich, 1989.
  15. Ershov, A. P., and Knuth, D. E. (Ed.) Algorithms in Modern Mathematics and Computer Science. Springer Lecture Notes in Computer Science, 1981.
  16. Greenleaf, N. Liberal constructive set theory. In Richman, F. Ed., Constructive Mathematics, Springer Lecture Notes in Mathematics, Vol. 873, 1981, pp. 213-240.
  17. Greenleaf, N. “Algorithms and proofs: mathematics in the computing curriculum”. ACM SIGCSE Bulletin 21 (1989), 268-272.
  18. Hallett, M. Cantorian Set Theory and Limitation of Size. Oxford University Press, 1984.
  19. Knuth, D.E. The Art of Computer Programming. Volume 1: Fundamental Algorithms. Addison-Wesley, 1973.
  20. Knuth, D.E. Algorithms in modern mathematics and computer science. In Algorithms in Modern Mathematics and Computer Science, Springer Lecture Notes in Computer Science, Vol 122, 1981, pp. 82-99. Revised (from ALGOL to Pascal) and reprinted in American Mathematical Monthly 92 (1985), 170-181.
  21. Lewis, H. and Papadimitriou, C. Elements of the Theory of Computation. Prentice-Hall, 1981.
  22. Martin-Löf, P. Constructive mathematics and computer programming. In Sixth International Congress for Logic, Methodology, and Philosophy of Science, North-Holland, 1982. Reprinted in Mathematical Logic and Programming Languages, Hoare, C. A. R. and Shepherdson, J. C. (eds.), Prentice-Hall, 1986.
  23. Moerdijk, I. “Review of Mathematical Intuitionism. Introduction to Proof Theory”. Bull. Amer. Math. Society 22 (1990), 301-304.
  24. Murthy, C. Classical Proofs as Programs: How, What, and Why. These Proceedings, 1991.
  25. Myers, J. P., Jr. “The central role of mathematical logic in computer science”. ACM SIGCSE Bulletin 22 (1990), 22-26.
  26. Rado, T. “On non-computable functions”. Bell Sys. Tech. Journal (1962), 887-894.
  27. Stewart, I. “The ultimate in undecidability”. Nature 332 (10 March 1988), 115-116.
  28. Troelstra, A. S. “Intuitionistic extensions of the reals”. Nieuw Arch. Wisk. 28 (1980), 63-113.
  29. Wittgenstein, L. Remarks on the Foundations of Mathematics. Basil Blackwell, 1956. Translated by G. E. M. Anscombe.


via:

学生社团系统-学生社团“一站式”运营管理平台-学生社团管理系统-基于SSM的学生社团管理系统-springboot学生社团管理系统.zip-Java学生社团管理系统开发实战-源码 更多学生社团系统: SpringBoot+Vue学生社团“一站式”运营管理平台源码(活动管理+成员考核+经费审批) Java学生社团管理系统开发实战:SSM升级SpringBoot(招新报名+场地预约+数据看板) 基于SpringSecurity的社团管理APP(移动端签到+权限分级+消息推送) 企业级社团数字化平台解决方案(SpringBoot+Redis缓存+Elasticsearch活动搜索) 微信小程序社团服务系统开发(活动直播+社团文化墙+成员互动社区) SpringBoot社团核心源码(多角色支持+工作流引擎+API接口开放) AI赋能社团管理:智能匹配兴趣标签+活动热度预测+成员贡献度分析(附代码) 响应式社团管理平台开发(PC/移动端适配+暗黑模式+无障碍访问) 完整学生社团系统源码下载(SpringBoot3+Vue3+MySQL8+Docker部署) 高校垂直领域社团平台:百团大战系统+社团星级评定+跨校活动联盟 适用对象:本代码学习资料适用于计算机、电子信息工程、数学等专业正在做毕设的学生,需要项目实战练习的学习者,也适用于课程设计、期末大作业。 技术栈:前端是vue,后端是springboot,项目代码都经过严格调试,代码没有任何bug! 核心管理:社团注册、成员管理、权限分级 活动运营:活动发布、报名签到、场地预约 资源服务:经费申请、物资管理、文档共享 数据分析:成员活跃度、活动效果评估、社团影响力排名
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值