在以前几篇咱们讨论的语法、语义、命名、类型和抽象适用于全部语言。然而咱们的注意力都主要集中在命令式语言上,如今这篇来看看其它范式的语言。函数式和逻辑式语言是最主要的非命令式语言。html
命名和做用域问题出如今各类模型中,还有类型、表达式和选择与递归等控制流概念等等。全部语言都必须通过扫描、语法分析和语义分析,程序员
函数式程序设计将一个程序的输出定义为其输入的一个数学函数,在其中没有内部状态的概念,所以也没有反作用。函数式提供了一下特征,其中许多都是命令式语言中没有的:安全
咱们以Scheme为例子,来看一下概念markdown
(let ((a 3)
(b 4)
(square (lambda (x) (* x x)))
(plus +))
(sqrt (plus (square a) (square b))))
复制代码
特殊型let有两个或者多个参数,其中第一个参数是一些二元组的表,每一个二元组的表,每一个二元组中的第一个元素是名字,第二元素就是这个名字在let的第二个参数中表明的值。其他参数将按顺序求值,对于整个结构的求值将是最终参数的值数据结构
(cond ((< 3 2) 1) ((< 4 3) 2) (else 3)) 复制代码
cond的参数是一些二元组,它们将被从头至尾按顺序考虑。若是第一个二元组的第一个元素求值获得#t,那么整个表达式的值就是这个二元组的第二个元素的值并发
在以前的几篇已经提到了两种求职方式:应用序求值和正则序求值。和大多数命令式语言同样,Scheme在大多数状况下都是用应用序求值。函数
若是一个无反作用的函数在其任何一个参数是未定义的状况下也是未定义的,咱们就称它为严格。这种函数能够安全的对全部参数求值,因此其结果也将不依赖于求值顺序。oop
惰性求值使咱们能够获得正则序求值的优点,回忆一下咱们以前说的,惰性求值对实现无穷数据结构很是有用spa
若是一个函数以函数做为实际参数,或者返回函数做为值,那么它就是一个高阶函数。操作系统
好比Scheme的map函数
(map * '(2 4 6) '(3 5 7)) => (6 20 42)
复制代码
map将对这些表中的一组元素调用相应的函数
高阶函数主要的做用就是从现有的函数出发构造新函数
(define total (lambda (l) (fold + 0 1))) (total '(1 2 3 4 5)) (define total-all (lambda (l) (map tatal l))) (total-all '((1 2 3 4 5) (2 4 6 8 10) (3 6 9 12 15))) 复制代码
Curry化
柯里化是一个常见的操做,是用一个单参数函数取代一个多参数的函数,这个单参数函数返回一个函数
(define curried-plus (lambda (a) (lambda (b) (+ a b)))) ((curried-plus 3) 4) (define plus-3 (curried-plus 3)) (plus-3 4) 复制代码
除了其它用途以外,这种curry操做还使咱们可以给高阶函数传递一个部分求值函数
(map (curried-plus 3) '(1 2 3)) => (4 5 6)
复制代码
无反作用的程序设计是一种很是诱人的想法,从前面的几篇能够看出,反作用可能使程序难以阅读和编译。
不过,存在着许多经常使用的程序设计惯用形式,最正宗的反作用在其中扮演着核心角色。
咱们关注计算的函数式模型。命令式程序的计算主要是经过迭代和反作用,而函数式程序的计算主要是经过将参数代换到函数中。
函数式语言的相应模型是lambda演算,许多函数式语言倾向于在lambda演算的基础上扩充一些特征,包括赋值、I/O和迭代。
若是一个程序包含了多余一个活动的执行上下文。即多余一个控制线程,则称该程序是并发的。并发的出现至少有三方面的重要缘由:
在一个并发程序中,咱们将使用术语线程来指代那些程序员认为与其余线程并发的运行的活动实体。在大多数系统中,给定程序的线程是在操做系统所提供的一个或多个进程的顶部实现的。
/*
在任何并发的程序设计模型中,须要处理的两个最关键的问题就是通讯的同步。通讯指线程可用于得到其它线程产生的信息的各类机制。
同步
*/
写到通常发现很像以前操做系统写到的进程管理,就再也不重复了。放个连接
这一篇就稍微提了一下除了命令式语言以外的其它范式,还有像如今语言支持的并发模型。可是以前讨论的语法、语义、命名、类型和抽象适用于全部语言