Ocaml入门(4)

递归函数

函数当然可以递归,而且更鼓励用递归而不是循环。

不过,递归需要关键字声明出来。

utop # let rec sum lst = match lst with
  |[]-> 0
  |h::tail -> h + sum tail;;
val sum : int list -> int = <fun>   
utop # sum [1;2;3;4];;
- : int = 10  

看另一个例子,去掉相邻的重复元素。

utop # let rec rr lst = match lst with
  | []-> []
  | [x]-> lst
  | h1::h2::tail -> if h1=h2 then rr (h2::tail) else h1::rr tail;;
val rr : 'a list -> 'a list = <fun>    
utop # rr [1;2;2;3;3;3;4;5];;
- : int list = [1; 2; 3; 5]    

 选项

Option 是OCaml中常用的类型。它表示可能是某个值,或者可能什么都没有。

utop # let div x y =
  if y=0 then None else Some (x/y);;
val div : int -> int -> int option = <fun>  
utop # div 6 3;;
- : int option = Some 2  
utop # div 6 0;;
- : int option = None   

从Option类型的值中取得有效值,需要用“解构”来提取。

op # let Some x = div 9 3;;
Characters 4-10:
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched: None val x : int = 3

匹配成功,但编译器给出个语法上的警告,因为无法确定等号右边返回的就是个Some x 的形式,还可能是None呢。

局部绑定

utop # let x=5 in x * 2 + 1;;
- : int = 11 

x=5 的绑定只在in后的语句中有效。x并不是全局可访问的。

局部绑定是个表达式,最终返回一个值,就是in语句返回的值。

当然,局部绑定是可以嵌套的。

utop # let x = 5 in let y = 6 in x * x + y * y;;
- : int = 61  

记录和变体

utop # type pp = {x:int; y:int};;
type pp = { x : int; y : int; }  

记录与tuple相比,每个域有有个名字,这样就可以不按顺序给出每个域的值。

utop # let a = {y=3;x=4};;
val a : pp = {x = 4; y = 3}   

当然,可以采用解构赋值(更准确说,叫绑定)。

utop # let {x=vx} = a;;
val vx : int = 4 

解构也可出现在参数的位置。

op # let f {x=vx;y=vy} = vx*vx+ vy*vy;;
val f : pp -> int = <fun>  
utop # f {x=2;y=5};;
- : int = 29  

用在参数位置,可以简化。

utop # let f {x;y} = x*x+y*y;;
val f : pp -> int = <fun>  

可以像Option一样,新的类型也可以组合自多个类型。

utop # type ppp = {x:int;y:int;z:int};;
type ppp = { x : int; y : int; z : int; }  
utop # type p2p3 = P2 of pp | P3 of ppp;;
type p2p3 = P2 of pp | P3 of ppp  utop # let g p = match p with P2 {x;y} -> "p2" | P3 {x;y;z} -> "p3";; val g : p2p3 -> string = <fun>

 数组

op # let a = [|1;2;6;9|];;
val a : int array = [|1; 2; 6; 9|]  
utop # Array.length a;;
- : int = 4      
utop # a.(2) <- 100;;
- : unit = ()     
utop # a;;
- : int array = [|1; 2; 100; 9|]  

Ocaml 鼓励不使用变量的编程。而数组中的元素是可变的。

但Ocaml也提供了面向可变性编程,面向过程编程的手段。比如数组,for循环。

记录类型的值默认是不能更改的。但可以用mutable来修饰,变成可以修改的类型。

# type r1 = {mutable x:int; mutable y:int};;
type r1 = { mutable x : int; mutable y : int; }  
utop # let a = {x=5;y=10};;
val a : r1 = {x = 5; y = 10}   
utop # a.x <- 100;;
- : unit = ()      
utop # a;;
- : r1 = {x = 100; y = 10}   

Ref

如果记录中只有一个字段,其用法就如同其它语言中的普通变量。因为这种用法比较有代表性,Ocaml就预先做了个类型。测一下:

utop # let a = {contents=10};;
val a : int ref = {contents = 10}   

OCaml提供了预定义的一些函数(或运算符),使得操作更简单直观。

utop # let x = ref 0;;
val x : int ref = {contents = 0} 
utop # !x;;
- : int = 0     
utop # x := !x + 1;;
- : unit = ()     
utop # !x;;
- : int = 1 

for与while循环

utop # for i=1 to 10 do
  print_int i
done;;
utop # while !p<10 do
  p := !p + 1;
  print_int !p
done;;

 

posted @ 2015-09-02 16:04  可雷曼土  阅读(1248)  评论(0编辑  收藏  举报