当前位置: 首页 > 工具软件 > ocaml-jupyter > 使用案例 >

ocaml 2

翟越
2023-12-01
转换整数到浮点:float_of_int n
转换浮点到整数:int_of_float n

函数的定义
在Ocaml中,同其它强类型语言一样,函数取得一个预定义类型的参数并返回一个给定类型的值。函数的参数间简单的使用空格分开。
假如我们想定义下面的这些函数,它们的数学形式为:

double : x -> 2X
square : x -> x*x
cube : x -> x^3

我们该如何在Ocaml中实现它们呢:
  1. # let double = fun x -> 2. *. x ;;
  2. # let square = fun x -> x *. x ;;
  3. # let cube = fun x -> x ** 3. ;;

复制代码
从上面的语法中我们可以看出真正定义函数的部分是从"fun"开始的。而之前的 "let double = "是函数的名字。在Ocaml中也可以使用没有名字的函数。定义函数还可以使用另一种语法:
  1. # let double x = 2. *. x ;;
  2. # let square x = x *. x ;;
  3. # 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中这是很简单的:
  1. 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的组合,象下面我们将看到的那样:
  1. # compose double square 3. ;;
  2. - : float = 18.

  3. # compose square double 3.;;
  4. - : float = 36.

  5. (* 定义包含一个将参数除2的函数的组合 *)
  6. # let myfunc = compose square (fun x -> x /. 2.) ;;
  7. # myfunc 5. ;;
  8. - : float = 6.25

复制代码
这里,我定义函数myfunc是square函数与一个将输入的参数除2的无名函数的组合。

我们把例子写成下面的样子来展示compose返回函数:
  1. (* Define a composite with a function that divides its input by 2 *)
  2. # let myfunc f = compose square f ;;
  3. # myfunc (fun x -> x /. 2.) 5. ;;
  4. - : float = 6.25

复制代码
符号化
可以把compose函数定义成一个中缀操作符。操作符可以不包含字母。要将它用为中缀,要把它放入括号之间。如下:
  1. (* Define the infix operator composite *)
  2. # let (@) = compose ;;

  3. # (double@square) 3. ;;
  4. - : float = 18.

  5. # (square@double) 3.;;
  6. - : float = 36.

复制代码
问题:为什么square@double周围需要括号呢?

函数对链的处理
链是函数语言中的一个标准数据结构。使用标准库List.map可以方便让函数的处理一个链中的所有元素,而不用使用循环。如:
  1. (*create a list of floats *)
  2. # let v = [1.; 2.; 3.; 4.; 5.] ;;

  3. # List.map (myfunc@square) v;;
  4. - : float list = [0.25; 4.; 20.25; 64.; 156.25]

复制代码
为了避免每次都写List.map,可以将代码象下面这样重写:
  1. (* These new functions take a list of floats as their input and return a list of floats *)
  2. # let square= fun v -> List.map (fun x-> x *. x) v ;;

  3. # let myfunc = fun v -> List.map (square@(fun x -> x /. 2.)) v ;;

  4. # (myfunc@square) v;;
  5. - : float list = [0.25; 4.; 20.25; 64.; 156.25]
 类似资料:

相关阅读

相关文章

相关问答