赞
踩
图灵完备性应该是大家经常会听说的一个概念,所有的编程语言它必备的一个条件就是图灵完备性,图灵完备性最早的提出是由我们计算机界的老祖宗图灵,他在这个研究数学上的可计算性的时候提出的这样的一个概念,
图灵完备性有几个不同的表达方式,比如说跟图灵机完全等效的,这就是图灵完备的,当然这个定义特别的不直观,它虽然很严格,但是它并不直观,如果给大家一个直观的表述就是:“所有的可计算的问题都可用来描述的,这样的语言就是具备图灵完备性的”
经历了一代一代的计算机语言的发展,其实图灵完备性逐渐的收敛到了几个固定的模式。所有的命令式语言,基本上是从图灵机理论来的图灵完备性,所以它实现图灵完备的方式,要么是使用 goto 语句,要么是使用 if 语句加 while 语句,经过一些数学家的证明这两个模式都是可以实现完整的图灵完备性的,
然后这个声明式语言,那么他来自于另一个数学家的成果,叫做 lambda 演算,这是丘奇提出来的,lambda 演算你可以理解为它是数学上定义的一种所谓的 lambda 函数,它和我们今天的函数是比较相似的,但它的基本意思就是一种替换的关系,lambda 它可以通过递归来实现图灵完备,
这两位数学家都是在很早的时间相继发表的这个成果,所以在可计算性上面呢,基本上计算机语言也是有两个流派,一个是 goto 和 if 和 while,另一个是用递归来产生图灵完备性,这两个方式在很多现代语言里基本上是都支持的,所以大家在使用的时候可以去经常去判断它们的适用的场景,然后选择合适的方式去实现它,
咱们经常会说这个语言是个动态语言那个语言它是静态语言,然后有的时候我们说类型这个是动态类型,那个是静态类型,那动态和静态在计算机领域里面这个术语是什么意思呢?我们给大家一些直观的印象去讲这件事情,
动态其实你可以理解为它一定是在用户的设备上面去运行的或者是在在线的服务器上面去运行的,那么它运行的时机就是在产品实际的应用运行时,那么它在这个动态基本上对应了一个概念叫 run time 就是运行时,运行时的这个概念反过来它也跟我们前面的两个场景是非常的相关联的,
静态最显著的一个特征就是在程序员的设备上运行的,那么它的运行时机也就是在产品的开发时发生的,我们一般来说会把它称作静态,比如静态类型检查就是在你编写这段代码的时候你就已经可以获得类型的检查了,静态它通常也对应着一个术语叫 compound time 就是编译时,这个也来自于非常古老的一些编译型语言的这样的一个概念啊,
从 C 语言时代就开始流行这个 compound time 和 run time 这样的一种对应关系了,像 JavaScript 这种解释执行的语言其实它没有 compound time 的,咱们现在虽然有的也会用 webpack 去 build 一下,但是其实它是没有真正的 compound time 的,所以说其实今天这个 run time 跟 compound time 的对应已经不准确了,但是我们仍然会愿意沿用这个 compound time 的这个习惯认为 JavaScript 它也是有一个我们在开发时的这样的一个时间
我们也会有时候会用 compared time 的这个词来讲 JavaScript 的里面的一些特性
这就是所谓的动态与静态的区分了
关于类型系统其实非常的复杂,这里我还是给大家介绍一些基本的概念,首先是动态类型系统与静态类型系统,这个就是跟刚才我们去解释动态与静态是非常一致的。动态系统就是在用户的机器上,用户的内存里面能够找到的这个类型那么它就是动态类型系统,那与之相对的静态类型系统就是只在程序员编写代码的时候能够保留的类型信息,我们就叫它静态类型系统,典型的动态类型系统,比如 JavaScript 的就是动态类型系统,我们在代码里面,可以把这个类型当字符串去取出来,
typeof("string")
然后典型的静态类型系统就像 C++ 这种,它其实最终编译到目标机器的代码的时候,所有的类型信息都已经被丢掉了,所以说我们去区分动态和静态的,其实最简单的办法就是区分它在谁的电脑上能够保留下来啊,而像 Java 一类的语言呢,因为它提供了反射机制,所以我会更愿意把它称作一种半动态半静态的类型系统,就是在编译时主要的类型检查和这个类型的这个操作都已经在编译时被处理掉了,但是如果你想在运行时去获得这个类型的一些信息,你还是可以通过反射去获取的,这个就是一些比较新的语言会采取的一种方式,
然后还有一个就是强类型与弱类型,在很多时候常常跟动态与静态去混淆,其实强类型与弱类型它只是在说明在这个编程语言里类型转换发生的形式,
强类型的语言它的类型转化是不会默认发生的,像这个 JavaScript 就是一个典型的弱类型的语言,最著名的比如说我们的用一个 string 和一个 number 相加,那么我们的 JavaScript 引擎会默认的把 number 转换成 string 类型之后,最后给你得到 string,而像这个这种它是 JavaScript 里面的一个臭名昭著失败的语言特性,它在 string 和 boolean 之间,如果说你去运算的话,它还会先把这个 boolean 转成 number,然后再去跟 string 去做是否相同的对比,这是一个非常奇怪的设计
然后再说回这个类型,就往往会产生一些复合类型,比如说我们可以定一个结构体一个对象,那么它的这个 a 属性,它必须属于类型 T1,然后我们有一些函数,因为像 JavaScript 语言,它的函数是可以作为参数传递的,所以这个函数也有个类型,这个我们一般把它称作函数签名,函数签名里包含参数类型和返回值类型两个部分。那参数类型它又是一个列表,所以说函数类型它可能就会有这个 T1,T2,然后变成 T3 这样的一种形式,然后就是子类型典型的语言就是 C++,它会有这个字类型的一个概念,当然了,所有的基于类的面向对象的语言呢,它都会把类的结构关系变成类型的关系啊,注意类和类型,其实是两个概念,那么有了子类型的这个概念呢,所以说在做类型转换的时候它就会有一些默认的行为,比如说能用父类型的地方它都能用子类型,
然后还有一种就是泛型,在一些语言里面现在又多了一种范式叫做泛型编程,还可以把类型当做一个参数一样的东西去传递给我们的某一段代码结构,这个代码结构有可能是类,也有可能是函数,分别对应着泛型类和泛型函数,然后泛型跟子类型相结合就会产生什么逆变,协变这样的东西,有兴趣的同志可以去看 TypeScript 泛型相关的内容
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。