转换整数到浮点:float_of_int n
转换浮点到整数:int_of_float n
函数的定义
在Ocaml中,同其它强类型语言一样,函数取得一个预定义类型的参数并返回一个给定类型的值。函数的参数间简单的使用空格分开。
假如我们想定义下面的这些函数,它们的数学形式为:
double : x -> 2X
square : x -> x*x
cube : x -> x^3
我们该如何在Ocaml中实现它们呢:
- # let double = fun x -> 2. *. x ;;
- # let square = fun x -> x *. x ;;
- # let cube = fun x -> x ** 3. ;;
复制代码
从上面的语法中我们可以看出真正定义函数的部分是从"fun"开始的。而之前的 "let double = "是函数的名字。在Ocaml中也可以使用没有名字的函数。定义函数还可以使用另一种语法:
- # let double x = 2. *. x ;;
- # let square x = x *. x ;;
- # let cube x = x ** 3. ;;
复制代码
注意*号后面的点。它告诉编译器函数仅接受浮点型的参数(因此它也返回一个浮点)。对于函数square如果*号后没有这个点函数将只接受整形参数。这种根据函数使用的语法来推断类型的过程叫作类型推论。这可以使用代码更加易读。为了避免误解,Ocaml的翻译器总是告诉你它推导出的类型。在后面的例子中我将省略这些输入的信息。
函数是first-class类型
这是Ocaml中最有趣的特性,函数是first-class类型,更确切的说,它们可以传递给另一个函数并且可以象任何一般类型(象是整形、浮点、字符串)那样被返回。
让我们通过一个例子来解释它,假设我们希望定义一个由两个函数f与g组合而成的函数,数学定义如下:
f o g : x -> (f o g) (x)= f(g(x))
在Ocaml中这是很简单的:
- let compose f g = fun x -> f(g(x)) ;;
复制代码
如果你够细心,你将注意到几件事:
1. 语法与之前的数学定义非常接近。
2. 我们不需要将x作为一个变量传递给compose函数,我们只要把f与g作为参数传递给compose函数。Ocaml的类型检查器将根据语法x->f(g(x))推导出f与g必须是函数。这里的x是一个虚变量,称为约束变量。
3.comopse函数实际上返回一个函数,是f与g的组合,象下面我们将看到的那样:
- # compose double square 3. ;;
- - : float = 18.
- # compose square double 3.;;
- - : float = 36.
- (* 定义包含一个将参数除2的函数的组合 *)
- # let myfunc = compose square (fun x -> x /. 2.) ;;
- # myfunc 5. ;;
- - : float = 6.25
复制代码
这里,我定义函数myfunc是square函数与一个将输入的参数除2的无名函数的组合。
我们把例子写成下面的样子来展示compose返回函数:
- (* Define a composite with a function that divides its input by 2 *)
- # let myfunc f = compose square f ;;
- # myfunc (fun x -> x /. 2.) 5. ;;
- - : float = 6.25
复制代码
符号化
可以把compose函数定义成一个中缀操作符。操作符可以不包含字母。要将它用为中缀,要把它放入括号之间。如下:
- (* Define the infix operator composite *)
- # let (@) = compose ;;
- # (double@square) 3. ;;
- - : float = 18.
- # (square@double) 3.;;
- - : float = 36.
复制代码
问题:为什么square@double周围需要括号呢?
函数对链的处理
链是函数语言中的一个标准数据结构。使用标准库List.map可以方便让函数的处理一个链中的所有元素,而不用使用循环。如:
- (*create a list of floats *)
- # let v = [1.; 2.; 3.; 4.; 5.] ;;
- # List.map (myfunc@square) v;;
- - : float list = [0.25; 4.; 20.25; 64.; 156.25]
复制代码
为了避免每次都写List.map,可以将代码象下面这样重写:
- (* These new functions take a list of floats as their input and return a list of floats *)
- # let square= fun v -> List.map (fun x-> x *. x) v ;;
- # let myfunc = fun v -> List.map (square@(fun x -> x /. 2.)) v ;;
- # (myfunc@square) v;;
- - : float list = [0.25; 4.; 20.25; 64.; 156.25]