目录
1.函数式编程(Functional Programming/FP)
2.OCaml中的基本数据类型(Basic Data Type)
1.函数式编程(Functional Programming/FP)
编程范式包括命令式编程、声明式编程、面向对象编程和函数式编程。
命令式编程:Imperative Programming,描述实现目标的一个个过程,命令“机器”做某个行为,更关注过程,如何一步一步实现行为。
声明式编程:Declarative Programming,描述需要实现的目标,如:利用SQL语句在数据库中查找满足查询要求的记录,SQL语句只需描述查询的要求而不必考虑具体的查询过程是怎样的。
面向对象编程:Object Oriented Programming,模拟人类的思维方式,将现实世界抽象为类,将现实世界的具体实体抽象为对象。
函数式编程:Functional Programming,函数式编程就是编写函数并将他们组合成更复杂的函数,核心概念为函数,将运算过程编写成一系列的函数调用。函数式编程语言有纯函数性语言(pure functional language)如Haskell,和非纯函数性语言(impure functional language)如OCaml、Lua、Python、Julia等。函数式编程的重要特性是不可变性。
OCaml中仍然保留了一些命令式特性,如仍然能够使用循环和改变值。
以下链接是Ocaml官方文档,是学习OCaml的资源之一,同时还包含安装OCaml的所有细节。
2.OCaml中的基本数据类型(Basic Data Type)
OCaml包括5种基本数据类型,分别为int,float,char,string,bool
int:64位处理器上为63位有符号整数,32位处理器上为31位有符号整数
float:IEEE双精度浮点数,相当于C语言中双精度浮点数double
char:8位字符,如'x'、'b'、'q'、'p'等
string:字符串(8位字符序列),如"hello"、"world"。字符串不仅仅是字符的列表,他们有自己更有效的内部表达方式,字符串是不可变的。
bool:布尔值,其值为true或者false
还有一种比较特殊的类型:unit
unit类型指示缺少某特定值,以()的形式表示;unit类型只有一个值,不存在任何其他值或者不需要其他值时,该值作为一个占位符。类似于C++等中地void值
3.运算符号(Operator)
3.1算术运算符
运算符 | 表达式 | 作用 | 注意 |
+ | op1+op2 | 两整数相加 | 该运算符左右的两个数必须为int类型的数,不能为其他类型 |
- | op1-op2 | 两整数相减 | 同上 |
* | op1*op2 | 两整数相乘 | 同上 |
/ | op1/op2 | 两整数相除 | 同上 |
+. | op1+.op2 | 两浮点数相加 | 该运算符左右的两个数必须为float类型的数,不能为其他类型 |
-. | op1-.op2 | 两浮点数相减 | 同上 |
*. | op1*.op2 | 两浮点数相乘 | 同上 |
/. | op1/.op2 | 两浮点数相除 | 同上 |
** | op1**op2 | 浮点指数 | 无 |
mod | op1 mod op2 | 整数求其余数 | 作用与C语言中的%一样 |
land | op1 land op2 | 按位与 | 作用与C语言中的 & 一样 |
lor | op1 lor op2 | 按位或 | 作用与C语言中的 | 一样 |
lxor | op1 lxor op2 | 按位异或 | 作用与C语言中的 ^ 一样 |
lsl | op1 lsl op2 | op1逻辑左移op2位 | Logical Shift Left,低端空出的位补0 |
lsr | op1 lsr op2 | op1逻辑右移op2位 | Logical Shift Right,高端空出的位补0 |
asr | op1 asr op2 | op1 算数右移op2位 | Arithmetic Shift Right,移位过程中保持符号位不变(即如果源操作数为正数,则高端空出的位补0,否则补1) |
注意:OCaml中的浮点数的相关运算符号与整数的相关运算符号有差别,浮点数的相关运算符号大多在整数的相关运算符号后加上点"."。OCaml中不存在自动类型转换,这不同于其他的一些编程语言如C和C++等,C和C++中可以存在诸如(1+3.14)这类的表达式,但在OCaml中,该表达式会报错。OCaml是安全的、健壮的,必须按照上述表格的要求的数据类型进行相关运算。
以下是一个典型的错误(误以为OCaml中存在自动类型转换):
以下所有代码块:#后为代码部分,下面为运行后的结果
# let x = 1 + 3.14;;
(* 这是注释;注释的方法为括号内加入一对星号 *)
报错:Error: This expression has type float but an expression was expected of type int
修改:
方法(1)let x = 1. +. 3.14
方法(2)let x = float_of_int 1 +. 3.14
方法(2)为类型转换——type1_of_type2(type1为转换后的类型,type2为转换前的类型)
3.2逻辑运算符
运算符 | 表达式 | 作用 | 注意 |
= | op1=op2 | 等于 | op1和op2值相等 |
<> | op1<>op2 | 不等于 | op1和op2值不相等 |
== | op1==op2 | 等于 | 物理等于(需要op1和op2为同一个对象,可认为是指向同一个内存空间) |
!= | op1!=op2 | 不等于 | 物理不等于 |
< | op1<op2 | 小于 | 无 |
<= | op1<=op2 | 小于等于 | 无 |
> | op1>op2 | 大于 | 无 |
>= | op1>=op2 | 大于等于 | 无 |
&& | exp1&&exp2 | 与 | 无 |
|| | exp1||exp2 | 或 | 无 |
not | not exp | 非 | 无 |
3.3其他操作符
运算符 | 作用 | 实例 |
^ | 字符串连接操作符 | "hello"^"world" |
:: | cons operator:将一个元素添加到一个列表的开头 | 4::[3;4;8;10] |
@ | append operator:将两个列表合并为一个列表 | [3;6;2;]@[1;0;2] |
:= | 引用赋值运算符 | let x= ref 0 x:=100 (* val x : int ref = {contents = 0} *) |
! | 得到可变数据类型的值 | !x (* 接着上一个例子,!x表示得到x的值,即为100 *) |
4.表达式(Expression)
4.1表达式基础知识
表达式:由数字、算符、括号、变量等以能求得数值的有意义排列方法所得的组合。
下面的代码即为一个表达式
# let x = 1 + 2;;
val x : int = 3
注意:在OCmal中,值无法被改变。且为了方便编写程序,往往会使用let对表达式的结果赋予一个名字。具体如下:
4.2 let的用法
(1)使用let给表达式的结果命名
# let x = 8*9;;
val x : int = 72
(* 这是顶级绑定,在全局起作用。
类似其他编程语言中的全局变量 *)
(2)使用let给单个参数或多个参数的函数命名
# let f x = x + 1;;
val f : int -> int = <fun>
(* 这是单个参数的函数,作用为将输入参数加1后输出。
该函数的名字为f,输入参数为x,输出参数为x+1 *)
# let my_add2 (x,y) = x + y;;
val my_add2 : int * int -> int = <fun>
(* 这也是单个参数的函数,作用为求和x与y。
my_add2为函数名,(x,y)为一个int*int的元组,
故也为一个输入参数,而非两个输入参数。元组后续会进行讲解。
至于为何能确定是int*int的元组是因为函数的返回结果是x+y,
"+"只能用于将两个int类型的数据相加,故可以推断x和y一定为int类型的数据 *)
# let my_add x y = x + y;;
val my_add : int -> int -> int = <fun>
(* 该函数为2个参数的函数,作用为求和。
my_add为函数名,x y为输入参数,x+y为输出参数。
多个参数直接分隔开即可 *)
(3)let的局部定义
# let x = 2 in x + 7;;
(* 此处x是局部绑定,只在x+7这个表达式中起作用。
类似于其他编程语言中的局部变量。in 后接这个局部绑定起作用的表达式 *)
5.函数(Function)
此处仅对函数进行基本介绍,后续会介绍递归函数、map函数、filter函数、zip函数等较难的函数。
概念:函数式编程中的函数概念与数学中的函数概念类似——即自变量映射为因变量(数据的映射),函数式编程的核心就是编写函数并将其组合成更复杂得函数。
要素:输入域、输出域、映射关系
注意:不能认为函数的输入域和输出域只能是数字。输入域和输出域可以十分复杂——如输入一张彩色图片,输出该图片的rgb三通道图。
定义:在函数式编程中,函数也被看作一种数据类型。两种定义方式完全等价。
定义方式1:
# let f x = x * x;;
val f : int -> int = <fun>
# let f x y = x + y;;
val f : int -> int -> int = <fun>
定义方式2:
# let f = (fun x->2*x);;
val f : int -> int = <fun>
# let f = (fun (x,y)->x+y);;
val f : int * int -> int = <fun>
调用方式:
(1)函数名后直接加参数,不需要括号,如 f 50
(2)匿名函数(函数没有被命名),如(fun x->2*x) 10
后续会持续更新复杂数据类型、模式识别、递归和其他重要函数等内容。