当前位置: 首页 > article >正文

类型系统下的语言分类与类型系统基础

类型系统是一种根据计算值的种类对程序语法进行分类的方式,目的是自动检查是否有可能导致错误的行为。
—Benjamin.C.Pierce,《类型与编程语言》(2002)

每当谈到编程语言时,人们常常会提到“静态类型”和“动态类型”。

类型(Typing)通常是开发者在选择语言时经常考虑的主题。

首先,我们简单讨论一下什么是静态类型和动态类型。

(动态类型与静态类型 Kolja Wilcke https://x.com/01k 的插图)

类型系统的基本概念

类型系统(Typing System)是一组规则,定义了如何管理变量、函数和数据的类型。

类型系统的主要目的如下:

  • 防止错误:防止使用错误类型的数据显示问题。
  • 代码稳定性:使程序行为更具可预测性。
  • 优化可能性:利用类型信息让编译器进行优化。

特别是静态类型(Static Typing)和动态类型(Dynamic Typing)的区别在于类型检查的时间点不同。

静态类型(Static Typing)

  • 在编译时(Compile-Time)检查类型。

  • 变量或函数的类型需要提前声明,编译时可以捕捉类型错误。

  • 代表性语言:C、C++、Java、C#、TypeScript、Kotlin

int age = "32"; // 编译错误发生。不能将字符串赋值给整数型变量

优点是可以提前防止类型错误,提高稳定性。

缺点是编写代码时需要提前声明类型,可能导致开发速度较慢。

动态类型(Dynamic Typing)

  • 在运行时(RunTime)检查类型。

  • 不需要提前声明变量的类型,类型在执行过程中确定。

  • 代表性语言:Python、JavaScript、Ruby、PHP

    age = 32 # 整数
    age = "Thirty-two" # 字符串(允许)

优点是编码灵活,开发速度快。
缺点是类型错误可能在运行时发生,调试困难。

用一句话总结,静态类型是证明某种错误不存在,而动态类型是从该错误中恢复。

那么,这一切是如何开始的呢?

首先,我们需要了解λ演算(Lambda Calculus)。

.基本数论问题中,有些问题可以通过找到一个有效的函数 f 来解决,这个函数可以根据 n 个正整数来计算。
这里,f(x1, x2, ..., xn) = 2 成立的充分必要条件是某个数论命题为真。
—Alonzo Church,《初等数论中的不可解问题》(1936)

λ演算是编程起点的一篇论文。

在这篇论文中,阿隆佐·邱奇首次正式提出了一个新的形式系统——λ演算。
邱奇利用λ演算将可计算性(Computability)这一直观概念进行了数学上的严格定义。
这与图灵机(Turing Machine)一起成为了定义计算能力的强大且有影响力的形式系统之一。

这篇论文的核心结果是解决了当时数学界的难题——判定问题(Entscheidungsproblem)的不可解性。
这篇论文还包含了函数式编程的基础概念,例如匿名函数(Anonymous Function)、高阶函数(Higher-Order Function)和函数应用(Function Application)。

λ演算虽然复杂,但许多数学家和计算机科学书籍作者的总结如下:

  • 将函数视为最基本的操作。
  • 仅通过变量、抽象和应用三个规则即可表达图灵完备性(Turing-Complete)。

然而,λ演算最初没有类型的概念,是一个可以接受“任何东西”的动态模型。
也就是说,早期的λ演算形式由于没有类型,与动态类型有相似之处,
这篇论文后来成为动态类型(Dynamic Typing)的基础。

*图灵完备性(Turing Completeness):具有图灵完备性的系统可以解决所有图灵机能解决的计算问题。
**图灵机(Turing Machine):由艾伦·图灵设计的一种抽象机器,现代计算机也遵循这种结构。

《简单类型理论的公式化》(1940年,Alonzo Church)

四年后,阿隆佐·邱奇提出了一个向λ演算添加“类型(Type)”的系统。

这标志着“类型系统”概念的首次出现,规定了每个变量和函数的输入/输出类型,

这项研究后来成为静态类型(Static Typing)形式的基础。

现在,我们已经看到了静态类型和动态类型的历史起点。

接下来,让我们看看λ演算到底是什么。

无类型λ演算(Untyped-λ-Calculus)

λx. x (恒等函数,identity function)
λx. λy. x + y (将两个值相加的函数)

-> 由于没有类型,可以传递任何值,但无法捕获类型错误!

有类型λ演算(Typed-λ-Calculus)

λx: Int. x + 1 // 接受整数输入并加1的函数
λx: Bool. if x then 1 else 0 // 将布尔值转换为整数

-> 明确声明类型以保证安全性!

眼尖的读者可能已经注意到,λ只是一个“接收输入的东西”。

更具体地说,λ是表示“匿名函数(Anonymous Function)”的符号,

λ表达式只是接收某些输入并执行特定操作后返回结果的函数!

让我们用中学数学来解释:

f(x) = x + 2

将其转换为λ表达式:

λx. x + 2

λx → 接收 x 作为输入。 x + 2 → 然后将输入加 2。

因此,λ可以简单理解为“接收输入的东西”。
就像我们在中学时学过的 x 和 y 一样,理解为插入值的概念。
共同点:
x 和 y 等数学变量也起到接收输入的作用。

λx. x + 2 中的 x 也像变量一样工作。

即,当某个值被提供时,它会被代入并计算函数。
区别:
x 和 y 是简单的变量,而λ还扮演“定义函数”的角色。

λx. x + 2 本身可以作为一个“匿名函数(Anonymous Function)”运行。

Lisp可以在一天内学会。但如果你懂Fortran,那需要三天。-Marvin Minsky

这些概念在高级语言从汇编语言进化的过程中得以实现,

那就是FORTRAN和Lisp。

FORTRAN1957静态类型编译时类型检查执行速度快
Lisp1958动态类型运行时决定类型灵活的数据结构

FORTRAN - 静态类型的开端
1957年为科学计算发明的第一种高级语言。

特点

  • 采用静态类型系统
  • 在编译时进行类型检查

Lisp - 动态类型的开端
1958年:约翰·麦卡锡(John McCarthy)开发的函数式编程语言

特点

  • 采用动态类型系统
  • 在运行时进行类型检查

语言的历史无穷无尽,因此简单总结一下,
静态类型在FORTRAN中通过编译时类型检查的方式实现,
动态类型则通过运行时动态决定类型并在执行过程中更改类型的方式实现。

补充一句,FORTRAN引入的类型系统并不是严格的类型系统,
严格的静态类型出现在ALGOL系列中,类型系统本身也经历了几十年的不断发展,

但基本上静态类型和动态类型的大框架一直保持不变。

然后,之后将静态类型和动态类型分开,

再进一步分类,让我们来看看这些分类方法。

(华盛顿大学CSE583)

按类型推断分类

public class TypeInferenceExample1 
{public static void main(String[] args) {// 显式类型声明 (传统方式)int number = 10;  // 声明一个整数类型的变量double pi = 3.14;  // 声明一个双精度浮点数类型的变量String message = "Hello, Type Inference!";  // 声明一个字符串类型的变量// 类型推断 (使用 var 关键字)var inferredNumber = 20; // 推断为 int 类型var inferredPi = 3.14159; // 推断为 double 类型var inferredMessage = "Welcome to Java!"; // 推断为 String 类型// 输出变量的值System.out.println("Number: " + number + ", Inferred Number: " + inferredNumber);System.out.println("Pi: " + pi + ", Inferred Pi: " + inferredPi);System.out.println("Message: " + message + ", Inferred Message: " + inferredMessage);}
}

(示例是Java著名的强类型推断关键字var)

  • 类型推断(Type Inference)是指程序员无需显式声明类型,编译器(或解释器)通过上下文(Context)或代码结构分析,自动推断变量、函数、表达式的类型的功能。

《类型与编程语言》一书中,

这部分内容以类型重建(Type Reconstruction)的形式出现,类型推断(Type Inference)一词与其混用,

类型重建(Type Reconstruction)被解释为类型推断(Type Inference)的一种形式。

类型推断(Type Inference)

  • 编译器能够完全推断类型的情况

类型重建(Type Reconstruction)

  • 已知部分类型信息,需要推断其余部分的情况

强类型系统提供了更安全的编程,但牺牲了灵活性。

无论如何,尽管各种语言使用不同的类型系统,但基本上分为

强类型系统和弱类型系统。

强类型系统

  • 类型转换(Implicit casting)受到严格限制。

弱类型系统

  • 类型转换自由,可能会导致意外行为。

为了更深入地理解这一点,让我们解释一下Hindley-Milner类型系统。

按Hindley-Milner系统应用与否分类

(表示Hindley-Milner类型系统的规则)

規則

說明

與 Hindley-Milner 類型系統的關係

[Var] 變數規則

環境(Γ)中存在的變數 x 具有類型 σ。

推斷變數類型的基本規則

[App] 函數應用規則

如果 e0 是 τ → τ' 類型,且 e1 是 τ 類型,那麼 e0 e1 是 τ' 類型。

定義函數應用時如何推斷類型

[Abs] Lambda 抽象規則

如果 Lambda 函數 λx.e 的 x 是 τ 類型,那麼結果是 τ' 類型。

基於 Lambda 演算的函數類型推斷方式

[Let] let 綁定規則

在 let x = e0 in e1 中,x 具有 e0 的類型。

ML 系語言中通過 let 進行類型推斷的方式

[Inst] 實例化規則

如果類型 σ' 是 σ 的實例 (⊑),那麼 e 可以具有 σ 類型。

與多態性(Polymorphism)類型推斷相關

[Gen] 多態性泛化規則

如果 e 具有類型 σ,並且 α 不是自由變數(free(Γ)),那麼 e 可以具有 ∀α.σ 類型。

解釋 Hindley-Milner 的 Let-Polymorphism

Hindley-Milner系统提供了强大的类型推断功能。

基于约束的类型系统 Constraint-Based Typing)

基于约束的类型系统是一种在类型推断过程中收集约束,然后批量解决这些约束(Constraint)的方法。
即,先收集所有必要的关系(约束条件),然后解决问题以确定最终类型。
在函数应用时不立即匹配类型,而是先收集类型约束(Constraint),稍后统一解决(Unification)。

之后,根据开发者是否在代码中显式声明类型(Explicit),或者由编译器/解释器自动推断(Implicit),
语言被进一步分类。

显式类型系统(Explicit Typing)

  • 开发者需要显式声明类型
  • 代码可读性好,但代码可能变长
  • 编译器能准确预测类型,因此错误较少

隐式类型系统(Implicit Typing)

  • 不需要显式声明类型,编译器自动推断
  • 代码简洁,但可读性可能下降
  • 如果推断出错,调试可能困难

也就是说,显式类型系统保证类型安全性,但代码可能冗长;隐式类型系统代码简洁,但可能出现意外的类型推断问题!

现在,基于此分类,让我们对现代常用语言进行分类。

語言

靜態/動態

強/弱類型

明示/暗示

是否適用 Hindley-Milner

特點

C

靜態

明示

類型轉換(Implicit Cast)自由(如 int → double)

C++

靜態

明示

與 C 相似,但支持部分類型推斷(例如 auto 關鍵字)

Java

靜態

明示

支持 var,但並非完整的類型推斷系統

C#

靜態

明示/暗示

支持 var 和 dynamic 關鍵字,部分支持動態類型

Go

靜態

暗示

使用 := 運算符進行類型推斷

Rust

靜態

暗示

部分適用

使用 let 關鍵字,類型推斷能力強

Swift

靜態

暗示

部分適用

類型推斷能力強,支持 let 和 var

Kotlin

靜態

暗示

部分適用

提供比 Java 更強大的類型推斷

Haskell

靜態

暗示

完全適用

基於 Hindley-Milner 的完整類型推斷

OCaml

靜態

暗示

完全適用

與 Haskell 類似的類型系統

TypeScript

靜態

明示

JavaScript 的靜態類型版本

Python

動態

暗示

運行時類型檢查,typing 模塊支持部分靜態類型

JavaScript

動態

暗示

== 和 === 運算符差異存在,隱式轉換能力強

Ruby

動態

暗示

類型轉換嚴格(例如 "5" + 5 不可能)

Lisp

動態

暗示

在動態類型語言中,類型非常靈活

一种不影响编程思维方式的语言不值得学习。 —Alan J.Perlis

编程语言的类型系统不仅仅是一个技术工具,更是思想和哲学的结晶。
从阿隆佐·邱奇的λ演算开始,经过FORTRAN和Lisp的对立,
静态类型追求稳定性,动态类型追求灵活性,形成了两条主线。
这两条主线在几十年间相互竞争、融合,奠定了现代语言的基础,并逐渐发展出渐进类型这一新的融合趋势和哲学。

在选择语言之前,我们通常根据目标行业常用的库和框架来选择语言。
但如果理解了类型系统,就可以基于语言的设计意图,更深入地理解其衍生的库和框架,
从而获得选择适合问题的工具(编程语言)的智慧。

相关文章:

类型系统下的语言分类与类型系统基础

类型系统是一种根据计算值的种类对程序语法进行分类的方式,目的是自动检查是否有可能导致错误的行为。 —Benjamin.C.Pierce,《类型与编程语言》(2002) 每当谈到编程语言时,人们常常会提到“静态类型”和“动态类型”。…...

力扣-回溯-93 复原IP地址

思路 用一个vector存放可能的结果&#xff0c;然后用一个变量判断插入点的数量&#xff0c;假设再最后一段后也插入点 代码 class Solution { public:vector<string> result;vector<string> path;int toNum(string s){int d 1;int result 0;for(int i s.size…...

SpringSecurity设置白名单

Spring Security 访问权限系列文章&#xff1a; 《SpringSecurity基于配置方法控制访问权限&#xff1a;MVC匹配器、Ant匹配器》 《SpringSecurity基于注解实现方法级别授权&#xff1a;PreAuthorize、PostAuthorize、Secured》 《SpringSecurity设置白名单》 白名单&#xff0…...

有没有使用wxpython开发的类似于visio或drawio的开源项目(AI生成)

有没有使用wxpython开发的类似于visio或drawio的开源项目 是的&#xff0c;有一些使用wxPython开发的类似于Microsoft Visio或draw.io&#xff08;现为diagrams.net&#xff09;的开源项目。wxPython 是一个跨平台的GUI工具包&#xff0c;它允许Python开发者创建桌面应用程序&…...

HTML之JavaScript DOM操作元素(2)

HTML之JavaScript DOM操作元素&#xff08;2&#xff09; 4.增删元素var element document.createElement("元素名") 创建新元素父元素.appendChild(子元素) 在父元素中追加子元素父元素.insertBefore(新元素,参照元素) 在特定元素之前新增元…...

前端八股——JS+ES6

前端八股&#xff1a;JSES6 说明&#xff1a;个人总结&#xff0c;用于个人复习回顾&#xff0c;将持续改正创作&#xff0c;已在语雀公开&#xff0c;欢迎评论改正。...

day58 第十一章:图论part08

拓扑排序精讲 关键&#xff1a; 先找到入度为0的节点&#xff0c;把这些节点加入队列/结果&#xff0c;然后依次循环再找。 #include <iostream> #include <vector> #include <queue> #include <unordered_map> using namespace std; int main() {int …...

【MySQL 一 数据库基础】深入解析 MySQL 的索引(3)

索引 索引操作 自动创建 当我们为一张表加主键约束(Primary key)&#xff0c;外键约束(Foreign Key)&#xff0c;唯一约束(Unique)时&#xff0c;MySQL会为对应的的列自动创建一个索引&#xff1b;如果表不指定任何约束时&#xff0c;MySQL会自动为每一列生成一个索引并用ROW_I…...

【C++】优先级队列宝藏岛

> &#x1f343; 本系列为初阶C的内容&#xff0c;如果感兴趣&#xff0c;欢迎订阅&#x1f6a9; > &#x1f38a;个人主页:[小编的个人主页])小编的个人主页 > &#x1f380; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 > ✌️ &#x1f91e; &#x1…...

解决elementUi el-select 响应式不生效的问题

情况一,字段类型不匹配 考虑option的value值的字段类型是否和api返回的字段类型一致&#xff0c;如果一个为字符串一个为数字类型是无法匹配上的 <template> <div><el-select v-model"value" size"large"style"width: 240px"&…...

List 接口中的 sort 和 forEach 方法

List 接口中的 sort 和 forEach 方法是 Java 8 引入的两个非常实用的函数&#xff0c;分别用于 排序 和 遍历 列表中的元素。以下是它们的详细介绍和用法&#xff1a; sort 函数 功能 对列表中的元素进行排序。 默认使用自然顺序&#xff08;如数字从小到大&#xff0c;字符…...

MusicGPT的本地化部署与远程调用:让你的Windows电脑成为AI音乐工作站

文章目录 前言1. 本地部署2. 使用方法介绍3. 内网穿透工具下载安装4. 配置公网地址5. 配置固定公网地址 前言 在如今快节奏的生活里&#xff0c;音乐不仅能够抚慰我们的心灵&#xff0c;还能激发无限创意。想象一下&#xff0c;在忙碌的工作间隙或闲暇时光中&#xff0c;只需输…...

小波变换背景预测matlab和python样例

小波变换使用matlab和python 注意1d和2d的函数区别。注意默认参数问题。最终三个版本结果能够对齐。 matlab load(wave_in.mat)% res: image of 1536 x 1536 th1; dlevel7; wavenamedb6;[m,n] wavedec2(res, dlevel, wavename);vec zeros(size(m)); vec(1:n(1)*n(1)*1) m…...

Unity通过Vosk实现离线语音识别方法

标注&#xff1a;deepseek直接生成&#xff0c;待验证 在Unity中实现离线语音识别可以通过集成第三方语音识别库来实现。以下是一个使用 Unity 和 Vosk&#xff08;一个开源的离线语音识别库&#xff09;的简单示例。 准备工作 Vosk&#xff1a;一个开源的离线语音识别库&am…...

【登月计划】 DAY2 中期:产品研发与设计验证(4-6)--《设计图纸如何从电脑飞进生产线?揭秘研发系统的 “暗箱操作”》

目录 四、乐高教学&#xff1a;拆解 CAD/CAE 与 PLM 的 “共生关系” 1. CAD 系统&#xff1a;工程师的 “数字画笔” &#x1f3a8; 2. CAE 系统&#xff1a;产品的 “虚拟实验室” &#x1f52c; 3. PLM 系统&#xff1a;设计的 “大管家” 五、装逼话术&#xff1a;设计…...

智能优化算法:莲花算法(Lotus flower algorithm,LFA)介绍,提供MATLAB代码

一、 莲花算法 1.1 算法原理 莲花算法&#xff08;Lotus flower algorithm&#xff0c;LFA&#xff09;是一种受自然启发的优化算法&#xff0c;其灵感来源于莲花的自清洁特性和授粉过程。莲花的自清洁特性&#xff0c;即所谓的“莲花效应”&#xff0c;是由其叶片表面的微纳…...

Qt开源项目获取

GitHub上超实用的Qt开源项目,码住不谢!🎉 宝子们,今天来给大家安利一波GitHub上超棒的Qt开源项目,无论是学习还是开发,都能找到超多灵感和实用工具,快来看看有没有你需要的吧!1. Qt-Advanced-Docking-System完美的Dock窗口布局解决方案,让你的窗口管理变得超级灵活。…...

Python 高级特性-迭代

目录 迭代 练习 小结 迭代 如果给定一个list或tuple&#xff0c;我们可以通过for循环来遍历这个list或tuple&#xff0c;这种遍历我们称为迭代&#xff08;Iteration&#xff09;。 在Python中&#xff0c;迭代是通过for ... in来完成的&#xff0c;而很多语言比如C语言&a…...

企业数据集成:实现高效调拨出库自动化

调拨出库对接调出单-v&#xff1a;旺店通企业奇门数据集成到用友BIP 在企业信息化管理中&#xff0c;数据的高效流转和准确对接是实现业务流程自动化的关键。本文将分享一个实际案例&#xff0c;展示如何通过轻易云数据集成平台&#xff0c;将旺店通企业奇门的数据无缝集成到用…...

基于GraphQL的电商API性能优化实战

以下是一个基于 GraphQL 的电商 API 性能优化实战案例&#xff0c;涵盖从问题分析到具体优化措施的实施过程&#xff1a; 一、初始问题分析 在电商场景下&#xff0c;随着业务发展&#xff0c;基于 GraphQL 的 API 出现了一些性能瓶颈。例如&#xff1a; 复杂查询导致响应时间过…...

UniApp SelectorQuery 讲解

一、SelectorQuery简介 在UniApp中&#xff0c;SelectorQuery是一个非常强大的工具&#xff0c;它允许开发者查询节点信息。通过这个API&#xff0c;我们可以获取到页面元素的尺寸、位置、滚动条位置等信息。这在处理动态布局、动画效果或是用户交互时尤为重要。 二、基本使用…...

数据库管理-第295期 IT架构与爆炸半径(20250221)

数据库管理295期 2025-02-21 数据库管理-第295期 架构与爆炸半径&#xff08;20250221&#xff09;1 术语新解2 硬件&#xff1a;存储VS本地盘3 数据库3.1 多模VS专用3.2 集中式VS分布式 4 公有云VS非公有云总结 数据库管理-第295期 架构与爆炸半径&#xff08;20250221&#x…...

基于WOA鲸鱼优化的BiLSTM双向长短期记忆网络序列预测算法matlab仿真,对比BiLSTM和LSTM

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a/matlab2024b 3.部分核心程序 &#xff08;完整版代码包含详细中文注释和操作步骤视频…...

DeepSeek私有化专家 | 云轴科技ZStack入选IDC中国生成式AI市场概览

DeepSeek 火爆全球AI生态圈&#xff0c;并引发企业用户大量私有化部署需求。 国际数据公司IDC近日发文《DeepSeek爆火的背后&#xff0c;大模型/生成式AI市场生态潜在影响引人关注》&#xff0c;认为中国市场DeepSeekAI模型的推出在大模型/生成式AI市场上引起了轰动&#xff0c…...

linux下软件安装、查找、卸载

目录 常见安装方式有三种&#xff1a; 1.源码安装。 2.rpm安装方式。 3.yum/apt工具级别安装。 对于前两种安装方式&#xff0c;因为软件可能有依赖关系&#xff08;安装的软件依赖于某些库&#xff0c;而这些库又依赖于某些库&#xff0c;这些都需要手动安装&#xff09;…...

npm在install时提示要安装python问题处理

使用npm\yarn\pnpm下载以来的时候&#xff0c;一直提示python异常&#xff0c;有的项目安装了python之后&#xff0c;下载依赖还是异常 而且旧版本项目使用python2,新的使用Python3…很烦 解决方案1&#xff1a;cnpm 安装教程&#xff1a; npm安装cnpm&#xff0c;解决node12\…...

Nginx代理ElasticSearch

1、将ES的账号:密码通过Base64加密 假设账号密码如下&#xff1a; 账号&#xff1a;elastic密码&#xff1a;elastichuayunworld.com echo -n elastic:elastichuayunworld.com | base64 ZWxhc3RpYzplbGFzdGljQGh1YXl1bndvcmxkLmNvbQ2、在 Nginx 配置中传递认证信息 locatio…...

如何将MySQL数据库迁移至阿里云

将 MySQL 数据库迁移至阿里云可以通过几种不同的方法&#xff0c;具体选择哪种方式取决于你的数据库大小、数据复杂性以及对迁移速度的需求。阿里云提供了多种迁移工具和服务&#xff0c;本文将为你介绍几种常见的方法。 方法一&#xff1a;使用 阿里云数据库迁移服务 (DTS) 阿…...

CSS基础(盒子模型的组成、内容溢出、隐藏元素的方式、样式的继承、元素的默认样式、布局技巧、元素之间的空白问题、行内块元素的幽灵空白问题)

文章目录 1. 盒子模型的组成1.1 内容区1.2 默认宽度1.3 内边距1.3.1 内边距属性1.3.2 复合属性1.3.3 单位1.3.4 注意事项 1.4 边框1.4.1 边框属性1.4.2 复合属性1.4.3 单方向边框1.4.4 边框样式1.4.5 注意事项 1.5 外边距1.5.1 外边距属性1.5.2 复合属性1.5.3 注意事项 1.6 外边…...

【第二节】C++设计模式(创建型模式)-抽象工厂模式

目录 引言 一、抽象工厂模式概述 二、抽象工厂模式的应用 三、抽象工厂模式的适用场景 四、抽象工厂模式的优缺点 五、总结 引言 抽象工厂设计模式是一种创建型设计模式&#xff0c;旨在解决一系列相互依赖对象的创建问题。它与工厂方法模式密切相关&#xff0c;但在应用…...