其他分享
首页 > 其他分享> > ocaml快餐教程(1) - 强类型语言

ocaml快餐教程(1) - 强类型语言

作者:互联网

ocaml快餐教程(1) - 强类型语言

Keep说:自律给我自由。
在汽车、航天、铁路等高可靠性要求的代码中,经常要求使用MISRA C/C++标准,该标准对于C语言中不同整数类型之间的赋值有比较严格的要求。有些同学对此叫苦不迭,觉得在没有意义的修复上浪费了太多的时间。

如果他们学习了ocaml语言的话,就会觉得这样的要求是天经地义的。在ocaml中,浮点数进行加减乘除运算做用的运算符跟整数是不一样的。

比如我们在ocaml中计算1+2,这个OK:

# 1 + 2 ;;
- : int = 3

我们想计算1.0 + 2.0,对不起,不能这么玩:

# 1.0 + 2.0 ;;
Error: This expression has type float but an expression was expected of type
         int

好吧,算你狠。那我计算两个长整数,用+可以吧?不行:

# 1L + 2L;;
Error: This expression has type int64 but an expression was expected of type
         int

64位不行,我用32位整数总可以了吧?不行:

# 1l + 2l;;
Error: This expression has type int32 but an expression was expected of type
         int

这个int,既不是int32,也不是int64,是像C语言的int一样的跟机器字长相关的整数。ocaml中,nativeint也是跟机器字长相关的,我们将其当成int使用还不行吗?没错,不行:

# let a1 = 1n ;;
val a1 : nativeint = 1n
# let a2 = 2n;;
val a2 : nativeint = 2n
# a1 + a2 ;;
Error: This expression has type nativeint
       but an expression was expected of type int

那么,我们想要给2个浮点数做加减乘除,该如何写呢?±/*后面也加上一个小数点:

# 1. +. 2. ;;
- : float = 3.

如果是其它那些整数类型想要进行运算,对不起,没有运算符了,请直接调用相关类的方法吧:

# Int32.add 1l 4l;;
- : int32 = 5l
# Int64.add 100L 2000L;;
- : int64 = 2100L
# Nativeint.add 50n 40n;;
- : nativeint = 90n

几句话迅速安装

在Ubuntu上,可以用apt install ocaml进行安装。
在MacOS上,可以使用Homebrew进行安装。

安装好之后,运行ocmal命令就可以进入交互模式。

ocaml的数值类型及其转换

我们将上面数值类型整理一下:

ocaml数值类型

知道了有什么,我们再列举下没有什么:

整数的最大值和最小值

很多同学对于数值类型有很多经验了,但是我还是要说,不要假设,在ocaml这种类型比较复杂的环境中,我们还是得看下真实的最大值和最小值是多少:

# Int.max_int;;
- : int = 4611686018427387903
# Int32.max_int;;
- : int32 = 2147483647l
# Int64.max_int;;
- : int64 = 9223372036854775807L
# Nativeint.max_int;;
- : nativeint = 9223372036854775807n
# Int.min_int;;
- : int = -4611686018427387904
# Int32.min_int;;
- : int32 = -2147483648l
# Int64.min_int;;
- : int64 = -9223372036854775808L
# Nativeint.min_int;;
- : nativeint = -9223372036854775808n

请注意,在64位系统上,nativeint与int64范围是一致的,但是int比它们少一位,所以差了两倍。

我们可以通过Sys.int_size来查看int类型的大小:

# Sys.int_size ;;
- : int = 63

需要注意的一点是,int类型是一直都有的,但是Int模块是4.08版本才引入进来的。这是相当晚近的事情,从ocaml 4.08才加入,这是2019年6月14日发布的。

在早于4.08版的ocaml上,Int是不存在的:

# Int.max_int;;
Error: Unbound module Int

比如Ubuntu 20.04现在使用的ocaml是4.08.1,将将及格。Ubuntu 18.04的ocaml还是4.05.0,还没满足这个要求。

无符号操作

虽然不支持无符号类型,但是ocaml为int32, int64和nativeint三种类型提供了几种无符号操作。这也是4.08版才引入进来的。

这其中包括:

例:

# Int32.unsigned_div 2147483648l 2l;;
- : int32 = 1073741824l

类型转换

其他整数类型,通过转换成int型来进行互转。
转成int的函数是to_int,把int转换成本类型是of_int。

我们看几个例子:

# Int32.to_int(30l);;
- : int = 30
# Int32.of_int(40);;
- : int32 = 40l

主要整数类型都提供了one和zero来表示1和0:

# Int64.to_int(Int64.one);;
- : int = 1
# Int64.of_int(Int.one);;
- : int64 = 1L

另外还有minus_one表示-1:

# Nativeint.to_int(Nativeint.minus_one);;
- : int = -1

浮点数

浮点数用Float类型来表示,这个模块是4.07版本引入的。

浮点数的边界有三个值:最大值,最小值,最小间距值:

# Float.max_float;;
- : float = 1.79769313486231571e+308
# Float.min_float;;
- : float = 2.22507385850720138e-308
# Float.epsilon;;
- : float = 2.22044604925031308e-16

4.08版开始,提供了is_integer函数来判断是不是一个小数点后为0的数:

# Float.is_integer(1e8);;
- : bool = true

那么在4.07版之前,用什么方式来做浮点数和整数的转换呢?我们有float_of_int和int_of_float两个函数来实现:

# float_of_int(100);;
- : float = 100.
# int_of_float(1e8);;
- : int = 100000000

前面讲过了,浮点数进行计算的时候,用的运算符是在整数运算符后加点的运算符:

# 1e8 +. 1e6;;
- : float = 101000000.
# 1e8 *. 1e-8;;
- : float = 1.

可以用科学计数法来表示浮点数,如果e后面是负数的话直接写负号,写括号是不能被识别的。

另外,Float提供了常用数学函数。如平方根,乘方,三角函数等基本数学函数都是由Float类提供的,如果整数需要进行此类计算,可以转化成Float再计算:

# Float.to_int( Float.sqrt( Int.to_float(144)));;
- : int = 12

比较运算符只有一套

ocaml提供了bool类型,只有两个值true和false。
bool值可以通过not运算符取反,&&进行与运算,|| 进行或运算。

ocaml也同样提供了=,<,>,>=,<=,<>几种比较运算符。
坏消息是,比较运算符要求前后的类型还是一致的。
好消息是,这次没有’<.'这样的判断浮点值的运算符了,int32, int64等类型的值也可以用这些运算符来进行比较了。

我们来看几个例子:

# 1 >= 2;;
- : bool = false
# 1l <= 5l ;;
- : bool = true
# 20L <> 10L ;;
- : bool = true
# 0.1 < 0.5 ;;
- : bool = true
# (20L > 10L) && (5l < 3l) ;;
- : bool = false

字符与字符串

本节的最后,我们看下字符与字符串。
字符和C语言一样,是个8位的数字,使用上是单引号加字符。但是,在其上没有定义算术运算。可以通过Char.code函数将字符转换成ASCII码:

# Char.code('A');;
- : int = 65

使用Char.chr函数将0~255的值转换成字符,例:

# Char.chr(32);;
- : char = ' '
# Char.chr(255);;
- : char = '\255'

ocaml的字符串不是字符数组,是一串用双引号括起来的字符。
字符串可以使用中文:

# let a = "中文";;
val a : string = "中文"

计算字符串长度通过String.length函数。
如果是中文的话需要注意,String.length获取的是实际占用的字节数,与编码方式相关:

# let a = "中文";;
val a : string = "中文"
# String.length a
  ;;
- : int = 6

string的最大长度可以通过Sys.max_string_length来获取:

# Sys.max_string_length;;
- : int = 144115188075855863

虽然不是字符数组,但是可以通过String.get函数来获取第n个字符,n从0开始计数:

# String.get "Hello" 2;;
- : char = 'l'
# String.get "Hello" 0;;
- : char = 'H'

标签:教程,Float,int,float,ocaml,整数,运算符,快餐
来源: https://blog.csdn.net/lusing/article/details/110006672