176

我正在阅读一个幻灯片,上面写着“JavaScript 未输入类型”。这与我认为的真实情况相矛盾,因此我开始挖掘以尝试了解更多信息。

JavaScript 是一种无类型语言吗?说 JavaScript不是无类型的,并提供了我熟悉和满意的各种形式的静态、动态、强类型和弱类型的示例......所以这不是要走的路。

所以我问了 JavaScript 的创造者 Brendan Eich,他说:

学术类型使用“无类型”来表示“无静态类型”。他们足够聪明,可以看到值具有类型(呃!)。上下文很重要。

专注于学术的计算机科学人员是否将“无类型”用作“动态类型”的同义词(这是否有效?)还是我缺少更深层次的东西?我同意 Brendan 的观点,即上下文很重要,但任何对解释的引用都会很棒,因为我目前的“转到”书籍并没有在这个主题上发挥作用。

我想确定这一点,这样我可以提高我的理解,因为即使是维基百科也没有提到这种替代用法(无论如何我都能找到)。如果我错了,我不想在将来使用该术语或质疑该术语的使用:-)

(我还看到一个顶级的 Smalltalker 说 Smalltalk 也是“无类型的”,所以这不是一次性的,这让我开始了这个任务!:-))

4

9 回答 9

153

是的,这是学术文献中的标准做法。要理解它,知道“类型”的概念是在 1930 年代在 lambda 演算的背景下发明的(事实上,甚至更早,在集合论的背景下),这会有所帮助。从那时起,出现了一个完整的计算逻辑分支,即所谓的“类型论”。程序设计语言理论就是建立在这些基础之上的。在所有这些数学上下文中,“类型”具有特定的、公认的含义。

术语“动态类型”是在很久以后才发明的——面对“类型”这个词的常见数学用法,它在术语上是矛盾的。

例如,这里是 Benjamin Pierce 在他的标准教科书Types and Programming Languages中使用的“类型系统”的定义:

类型系统是一种易于处理的句法方法,用于通过根据它们计算的值的种类对短语进行分类来证明不存在某些程序行为。

他还评论道:

有时会显式添加“静态”一词——例如,我们谈到“静态类型的编程语言”——以区分我们在此考虑的编译时分析类型与在语言中发现的动态或潜在类型,例如Scheme (Sussman and Steele, 1975; Kelsey, Clinger, and Rees, 1998; Dybvig, 1996),其中运行时类型标签用于区分堆中不同类型的结构。像“动态类型”这样的术语可以说是用词不当,可能应该用“动态检查”代替,但用法是标准的。

大多数在该领域工作的人似乎都同意这一观点。

请注意,这并不意味着“无类型”和“动态类型”是同义词。相反,后者是前者特定情况的(技术上具有误导性的)名称。

PS:FWIW,我碰巧既是类型系统的学术研究员,又是 JavaScript 的非学术实施者,所以我不得不忍受这种分裂。:)

于 2012-02-06T20:06:11.567 回答
73

我是一名专门研究编程语言的学术计算机科学家,是的,“无类型”这个词经常(错误地)以这种方式使用。保留这个词用于不带有动态类型标签的语言会很好,例如 Forth 和汇编代码,但是这些语言很少使用,甚至很少研究,而且说“无类型”要容易得多比“动态类型”。

Bob Harper 喜欢说像 Scheme、Javascript 等语言应该被视为只有一种类型的类型语言:值。我倾向于这种观点,因为它可以仅使用一种形式主义来构建一致的世界观。

PS 在纯 lambda 演算中,唯一的“值”是范式中的项,范式中唯一的封闭项是函数。但是大多数使用 lambda 演算的科学家都会添加基本类型和常量,然后你要么为 lambda 包含静态类型系统,要么马上回到动态类型标签。

PPS 致原发帖人​​:谈到编程语言,尤其是类型系统,维基百科上的信息质量很差。不要相信它。

于 2012-02-06T04:35:39.373 回答
44

我对其进行了调查,发现您的问题的答案很简单,令人惊讶的是,“是”:学术 CS 类型,或者至少其中一些,确实使用“无类型”来表示“动态类型”。例如,Programming Languages: Principles and Practices,第三版(Kenneth C. Louden 和 Kenneth A. Lambert,2012 年出版)这样说:

没有静态类型系统的语言通常称为无类型语言(或动态类型语言)。此类语言包括 Scheme 和 Lisp、Smalltalk 的其他方言以及大多数脚本语言,如 Perl、Python 和 Ruby。但是请注意,无类型语言不一定允许程序破坏数据——这只是意味着所有安全检查都是在执行时执行的。[…]

[链接] (注意:原文加粗)并以这种方式继续使用“无类型”。

我觉得这很令人惊讶(出于与 afrischke 和 Adam Mihalcin 给出的大致相同的原因),但你就是这样。:-)


编辑添加:"untyped languages"您可以通过插入Google 图书搜索找到更多示例。例如:

[…] 这是许多无类型语言的主要信息隐藏机制。例如 PLT Scheme [4] 使用生成structs,[…]

——雅各布·马修斯和阿迈勒·艾哈迈德,2008 [链接]

[…],我们对无类型函数语言 […] 进行了绑定时间分析。[…] 它已被实施并用于 Scheme 的无副作用方言的部分评估器中。然而,该分析足够通用,对于非严格类型的函数式语言(如 Haskell)有效。[…]

——查尔斯·康塞尔,1990 [链接]

顺便说一句,在查看这些搜索结果后,我的印象是,如果研究人员编写了一种“无类型”函数式语言,他很可能确实认为它是“无类型”,与无类型 lambda 具有相同的意义Adam Mihalcin 提到的微积分。至少,一些研究人员同时提到了 Scheme 和 lambda 演算。

当然,搜索并没有说明是否有研究人员拒绝这种识别,并且认为这些语言是“无类型的”。好吧,我确实找到了这个:

然后我意识到实际上没有循环,因为动态类型语言不是无类型语言——只是类型通常不会从程序文本中立即显现出来。

— 某人(我不知道是谁),1998 [链接]

但显然大多数拒绝这种认同的人不会觉得有必要明确地说出来。

于 2012-02-06T02:15:47.887 回答
10

无类型和动态类型绝对不是同义词。最常被称为“无类型”的语言是 Lambda Calculus,它实际上是一种统一的语言——一切都是函数,因此我们可以静态地证明一切的类型都是函数。动态类型语言有多种类型,但没有为编译器添加静态检查它们的方法,从而强制编译器插入对变量类型的运行时检查。

然后,JavaScript 是一种动态类型的语言:可以用 JavaScript 编写程序,使得某些变量x可以是数字、函数、字符串或其他东西(并确定哪个变量需要解决停机问题或其他问题)困难的数学问题),因此您可以应用于x参数,并且浏览器必须在运行时检查这x是一个函数。

于 2012-02-06T01:12:19.743 回答
6

这两种说法都是正确的,具体取决于您是在谈论值还是变量。JavaScript 变量是无类型的,JavaScript 值具有类型,并且变量在运行时可以覆盖任何值类型(即“动态”)。

在 JavaScript 和许多其他语言中,值而不是变量携​​带类型。所有变量都可以涵盖所有类型的值,并且可以被认为是“动态类型化”或“非类型化”——从类型检查的角度来看,一个没有/不可知类型的变量和一个可以采用任何类型的变量在逻辑上和实际上是等价的. 当类型理论家谈论语言和类型时,他们通常谈论这个——变量携带类型——因为他们对编写类型检查器和编译器等感兴趣,它们对程序文本(即变量)进行操作,而不是在内存中运行的程序(即价值观)。

相比之下,在其他语言(如 C)中,变量携带类型但值不携带。在像 Java 这样的语言中,变量和值都带有类型。在 C++ 中,一些值(具有虚函数的值)带有类型,而另一些则没有。在某些语言中,值甚至可以更改类型,尽管这通常被认为是糟糕的设计。

于 2012-02-06T12:58:59.857 回答
5

虽然大多数写类型的 CS 研究人员基本上只考虑将具有句法可派生类型的语言作为类型语言,但我们中有更多人使用动态/潜在类型的语言,他们对这种用法感到不满。

我认为有 3 种语言 [SIC]:

无类型 - 只有运算符决定值的解释 - 它通常适用于任何事情。示例:汇编程序、BCPL

静态类型 - 表达式/变量具有与之关联的类型,并且该类型在编译时确定运算符的解释/有效性。示例:C、Java、C++、ML、Haskell

动态类型 - 值具有与之关联的类型,并且该类型决定了操作符在运行时的解释/有效性。示例:LISP、Scheme、Smalltalk、Ruby、Python、Javascript

据我所知,所有动态类型语言都是类型安全的——即只有有效的运算符才能对值进行操作。但对于静态类型语言来说,情况并非如此。根据所使用的类型系统的能力,一些运算符可能只在运行时检查,或者根本不检查。例如,大多数静态类型语言不能正确处理整数溢出(添加 2 个正整数可以产生一个负整数),超出范围的数组引用要么根本不检查(C、C++),要么只检查运行。此外,某些类型系统非常弱,以至于有用的编程需要转义舱口(C 和家族中的强制转换)来更改表达式的编译时类型。

All of this leads to absurd claims, such as that C++ is safer than Python because it's (statically-typed), whereas the truth is that Python is intrinsically safe while you can shoot your leg off with C++.

于 2012-08-03T12:31:03.663 回答
4

这个问题都是关于语义的

如果我给你这个数据:12它是什么类型的?你无法确定。可能是整数 - 可能是浮点数 - 可能是字符串。从这个意义上说,它是非常“无类型”的数据。

如果我给你一种想象的语言,它可以让你在这个数据和其他一些任意数据上使用像“add”、“subtract”和“concatenate”这样的运算符,那么“type”就有点不相关(与我想象的语言)(例如: 可能会产生add(12, a)加上) 的 ascii 值。10912a

让我们谈谈C。C 几乎可以让您对任意数据进行任何操作。如果您使用的函数需要两个uints - 您可以转换并传递您想要的任何内容 - 并且这些值将简单地解释为uints。从这个意义上说,C 是“无类型的”(如果您以这种方式对待它)。

然而——说到布伦丹的观点——如果我告诉你“我的年龄是12”——那么12就有一个类型——至少我们知道它是数字的。有了上下文,一切都有一个类型——不管是什么语言。

这就是我一开始说的原因-您的问题是语义问题之一。“无类型”是什么意思?我认为 Brendan 在说“没有静态类型”时一针见血——因为这就是它可能的全部含义。人类自然地将事物分类。我们凭直觉知道汽车和猴子之间存在根本性的不同——我们从来没有被教导要做出这些区别。

回到开头我的例子——一种“不关心类型”(本身)的语言可以让你“添加”一个“年龄”和一个“名字”而不会产生语法错误......但是并不意味着这是一个合乎逻辑的操作。

Javascript 可以让你做各种疯狂的事情而不考虑它们“错误”。这并不意味着你正在做的事情在逻辑上是合理的。那是开发人员解决的问题。

在编译/构建/解释时不强制类型安全的系统/语言是“无类型”还是“动态类型”?

语义。

编辑

我想在这里添加一些东西,因为有些人似乎被“是的,但是 Javascript 确实有一些“类型””所吸引。

在我对别人回答的评论中,我说:

在Javascript中,我可以将对象构建为“猴子”,将对象构建为“人类”,并且可以将某些功能设计为仅对“人类”进行操作,而将其他功能设计为仅对“猴子”进行操作,并且还有一些人只在“带武器的东西”上。无论该语言是否曾被告知存在诸如“带武器的东西”这样的对象类别,它与汇编(“无类型”)和Javascript(“动态”)一样无关紧要。这完全是一个逻辑完整性的问题——唯一的错误是使用没有这种方法的东西。

所以,如果你认为 Javascript 在内部有一些“类型的概念”——因此是“动态类型”——并且认为这在某种程度上“与无类型系统明显不同”——你应该从上面的示例中看到任何“类型的概念”类型”它在内部实际上是无关紧要的。

例如,要使用 C# 执行相同的操作,我需要一个名为ICreatureWithArms或类似的接口。在 Javascript 中并非如此 - 在 C 或 ASM 中并非如此。

显然,Javascript 是否对“类型”有任何理解是无关紧要的。

于 2012-02-06T01:01:06.263 回答
2

我不是计算机科学家,但如果在 CS 社区(至少在科学出版物中)真的将“无类型”用作“动态类型”的同义词,我会感到相当惊讶,因为这两个术语描述了不同的概念。动态类型语言具有类型概念,它在运行时强制执行类型约束(例如,您不能在 Lisp 中将整数除以字符串而不会出错),而无类型语言在所有(例如汇编程序)。甚至关于编程语言的 Wikipedia 文章 (http://en.m.wikipedia.org/wiki/Programming_language#Typed_versus_untyped_languages) 也做出了这种区分。

更新:也许混淆来自这样一个事实,即某些文本在 Javascript 中“未键入变量”的程度(这是真的)。但这并不自动意味着该语言是无类型的(这将是错误的)。

于 2012-02-06T01:07:33.263 回答
1

同意布伦丹 - 上下文就是一切。

我的看法:

我记得大约在 2004 年,我很困惑,因为关于 Ruby 是无类型还是动态类型的争论不断。老派 C/C++ 人(我就是其中之一)在考虑编译器并说 Ruby 是无类型的。

请记住,在 C 语言中,没有运行时类型,只有地址,如果正在执行的代码决定将该地址处的任何内容视为不存在的内容,哎呀。这绝对是无类型的,并且与动态类型非常不同。

在那个世界里,“打字”是关于编译器的。C++ 具有“强类型”,因为编译器的检查更加严格。Java 和 C 更“弱类型化”(甚至有关于 Java 是强类型还是弱类型的争论)。在那个连续体中,动态语言是“无类型的”,因为它们没有编译器类型检查。

今天,对于练习程序员来说,我们已经习惯了动态语言,我们显然认为 untyped 意味着没有编译器或解释器类型检查,这将非常难以调试。但是有一段时间,这并不明显,在更理论的 CS 世界中,这甚至可能没有意义。

从某种意义上说,没有什么是无类型的(或者几乎什么都没有),因为你必须有一些意图来操纵一个值来编写一个有意义的算法。这是理论 CS 的世界,它不涉及如何为给定语言实现编译器或解释器的细节。所以“无类型”(可能,我不知道)在这种情况下完全没有意义。

于 2012-02-06T04:43:44.327 回答