编程语言与软件工程2021users.monash.edu
入门编程语言设计的七宗罪
Seven Deadly Sins of Introductory Programming Language Design (1996)
入门 · 约 30 分钟读完前置知识:基础编程经验、C/C++ 声明语法常识、编程语言设计常识
导读
这篇 1996 年的论文讨论入门编程语言设计中的常见错误,归纳为“七宗罪”,核心关切是语言设计中的取巧和语法选择如何增加初学者的认知负担。文中以 C/C++ 声明语法等为例,说明“声明模仿使用”这类看似优雅的设计可能反而混淆声明与使用、语义与写法。HN 评论则进一步争论语法复杂度、学习动机,以及用入门语言标准评价通用语言是否合适。
HN 关注点:是因为它触及编程语言设计中的经典张力:语法优雅或取巧与初学者可理解性之间如何取舍,以及教学语言该服务语言纯度还是学习动机。
HN 评论精选
这几条评论里:支持 2 质疑 2
支持C 声明语法是“聪明反被聪明误”的典型,给初学者制造了无谓障碍。
原文把 C/C++ 声明语法当作“聪明设计反噬”的首要例子:表面上是让声明模仿使用,实际上却破坏了用视觉区分语义差异的原则。今天看 C 的声明语法很怪异,尤其熟悉现代类型系统之后;“声明模仿使用”不仅催生“螺旋规则”,还带来 char *c 与 char* c 的写法困扰,以及 char* p, q 实际得到 char* p 和 char q 这类新手陷阱。
anyfoo查看英文原文
> The premier example of the adverse effects of cleverness in programming language design (and one which is obvious to programmers at all skill levels) must surely be the C/C++ declaration syntax [10]. On the surface, it seems like an excellent notion: let declarations mirror usage. Unfortunately, the very concept undermines the principle of visually differentiating semantic difference. Does it ever. From today's point of view, C's declaration syntax is just bizarre, especially if you spent some time with a "modern" type system[1]. The result of this declaration-mirrors-usage cleverness is not just the more encompassing insanity like the emergence of the "spiral rule", as found here: [2]. (Isn't it fun that that site promises to enable "any C programmer to parse in their head any C declaration!"? You know you have a problem when that's a novelty.) It's also the emerging little paper cuts, like the fact that it should be "char* c" with the * hugging the char because * modifies the type and so is part of it, but because of the "mirror usage" concept you better actually write "char *c", because that's how the parser groups it, as part of the variable. In effect, multiple declarations in one statement must have confused many novices, when they wrote something like "char* p, q", and surprisingly got a "char* p" and a "char q". > Students have enough trouble mentally separating the concepts of declaration and usage, without the syntax conspiring to blur that crucial difference. Yeah. I learned C in the 90s (and fortunately by now know exactly where to distribute my "volatile"s and "const"s in a complex type), but I still remember how confusing it was that the * practically did the opposite in declaration vs. usage. In a declaration it makes a pointer, in usage it dereferences it. Consider the very important difference between those: char *p = q; *p = q; Fun. [1] "Modern" in quotes, because one prime example, Haskell, is old enough to appear in this 1996 article. [2] http://c-faq.com/decl/spiral.anderson.html
支持语法方向性和解析习惯会影响初学者的心智模型,对入门语言是额外负担。
我大体同意。语法困惑是“用新语言思考”的巨大障碍,再叠加语义上的新概念,就形成意义与表达力的组合爆炸。lambda 记号的可读性可能死在“从左往右还是从右往左解析”的困惑里——我指的就是解析,人脑阅读词和符号的方式会影响其构建心智模型;a <- b 和 b -> a 都可能表示把 B 变成 A,但其中一个会被读成“a 由 b 推导而来”,语法和理解上并不相同。这不是说某门具体语言这样,而是对第一门或新语言来说,这是更高阶的问题。
ggm查看英文原文
I generally line up with this. Syntactic confusion is a huge barrier to "thinking" in a new computing language, now add to it by having to "think in new concepts" which lies in the semantics. Its a kind of combinatorial explosion of meaning and power of ideas. The expressive qualities of lambda notations can die in the inherent confusion "am I parsing this sentence-in-lambda left-to-right or right-to-left" -And I really do mean parse, the internal brain-model of "reading the words and symbols" informs how people construct a mental model of what they see. yes a <- b and b -> a could both mean B is transformed into A but one of them is actually "read" as "a is derived from b" which is different, syntactically, and in comprehension terms (I don't mean any computing language does this specific notation. I just mean, that how we comprehend this is subtly different, and in the case of first/new programming language, its a higher-order problem. New concepts, new notation)
质疑入门语言首要考虑实用性和早期成就感,而非语言技术细节。
学编程与其说靠语言,不如说靠人和动机。语言爱好者热衷类型系统和语法细节,但初学者需要跨过门槛并自我激励。选入门语言先问:它实用吗?学生第一周能否做出有成就感的东西?若不能,奖励机制太弱。打印斐波那契对多数学生没有吸引力,尾递归版更甚;能对外界输入做出反应、点 LED、发 HTTP 请求或发消息才有启发。我侄子写 Discord bot 在朋友上线时鸣笛吸引注意,不仅解决实用问题,还让他在同伴中获得地位,这是强动机。例如我通常推荐 Python。
bborud查看英文原文
Learning programming isn't so much about the language as it is about human beings and motivation. While language enthusiasts are very excited about type systems and technical details like syntax, what beginners need is to get over that initial threshold and to be able to self-motivate. The first question to ask when choosing a language is: is it useful for practical programming? Can the students do something that feels like an actual accomplishment within the first week? If it isn't, then you can't use it as a beginner's language because it has a weak reward mechanism. The reward is to be able to solve practical problems that mean something to the student. And this is critical in the initial weeks and months. Printing a fibonacci sequence is not rewarding for most students. It is for some, but in my experience, not most. Printing a fibonacci sequence with tail recursion even less so because a student will have no idea of why this may be important. Being able to write a program that meaningfully communicates with its surroundings to do work IS inspiring. Whether it is consuming input from the outside and doing something with it, blinking a LED, making an HTTP request, or sending a message. (Or in the case of my nephew: write a Discord bot that honks a horn when his friends are online and try to get his attention. Which didn't just solve a practical problem: it gave him status among his peers, which is a strong motivator) For instance: I tend to recommend Python as a first language. I don't like Python myself, but I recognize that it a) allows you to do practical things, b) it has a relatively simple syntax, and c) it doesn't really force a lot of fluff on you that "this will make sense later". It also allows you to postpone topics that initially just confuse students. Java, JavaScript, C, C++, Lisps and perhaps more esoteric languages are for later. Yes, I know people think some of these are "the right way" to start, but that's often the teachers focusing on their own interests and not focusing on the student. Bad teacher. Let's get people over the first couple of hurdles first, and then we can talk about what's next. But you always have to remind yourself that introductory programming is about humans.
质疑用入门语言标准批评本非入门设计的语言是错位;教学选择责任在课程而非语言。
但 C/C++、Ada 和 Haskell 从来就不是为入门教学设计的语言!抱怨它们违反入门语言的设计规则,是用错了标准。确实有教师尝试把它们当入门语言,但这不是语言本身的错。
AnimalMuppet查看英文原文
But C/C++, Ada, and Haskell were never intended to be introductory programming languages! Complaining about them violating rules for introductory languages is judging them by the wrong standard. (Yes, I know, instructors have tried to use them as introductory languages. That isn't the fault of the languages, though...)
相关资源
从这篇论文所有 HN 讨论帖的全部评论里整理出来的链接。
历次讨论
- 2021Hacker News 讨论帖150 分 · 110 评
同领域还值得读
Google 的软件工程(2017)
Software Engineering at Google (2017)
介绍了 Google 的软件工程实践,包括其单一代码库(monorepo)、几乎全部开发在主干进行而非分支、代码审查、构建系统 Blaze、协议缓冲区等工具与流程,并讨论了频繁重…
编程语言与软件工程2017 · 1,127 分 · 465 评 · 引用 15入门 · 约 45 分钟编辑精选Peter Naur:编程作为理论构建 (1985)
Peter Naur – Programming as Theory Building (1985)
Peter Naur 1985 年的经典论文《Programming as Theory Building》提出:编程的本质不是写代码或文档,而是在程序员头脑中构建对程序及其运行…
编程语言与软件工程2016 · 629 分 · 74 评入门 · 约 45 分钟编辑精选SciPy 1.0:Python 科学计算的基础算法
SciPy 1.0: fundamental algorithms for scientific computing in Python
这篇发表于 Nature Methods 的论文介绍了 SciPy 1.0——Python 科学计算生态的基石库,涵盖其核心算法模块(优化、积分、插值、线性代数等)、软件架构与社…
编程语言与软件工程2020 · 387 分 · 98 评入门 · 约 45 分钟编辑精选Lisp 的历史(1979)
History of Lisp (1979)
这是 Lisp 发明者 John McCarthy 于 1979 年为 HOPL(编程语言史)会议撰写的回顾文章,讲述 Lisp 的起源、设计动机与早期演进,文中也涉及 if 表…
编程语言与软件工程2018 · 352 分 · 44 评入门 · 约 45 分钟编辑精选使用 NumPy 进行数组编程
Array Programming with NumPy
这篇 Nature 文章介绍 NumPy 的数组编程模型及其在科学计算中的核心作用:以 ndarray 为中心,通过向量化操作让 Python 高效处理多维数组。
编程语言与软件工程2020 · 318 分 · 134 评入门 · 约 40 分钟编辑精选