ocaml学习

来源:互联网 发布:屏幕亮点修复软件 编辑:程序博客网 时间:2024/05/01 16:52

安装

Linux环境下

# apt-get install ocaml# apt-get install ledit# apt-get install tuareg-mode


Windows环境下

自行下载OCamlWinPlus


学习资源

  1. 《Practical OCaml》, Joshua B. Smith
  2. 官方文档
  3. 教程网站



笔记


一、注释

# (*comment*)


二、let给表达式的结果赋一个名字

1. 使用let定义一个整型:

# let inchesPerMile = 12*3*1760;;val inchesPerMile : int = 63360

2. 使用let定义一个函数:

# let cube (x:int) = x*x*x;;val cube : int -> int = <fun>
# let square x = x *. x;;val square : float -> float = <fun>
3. 多个参数:
# let sumsq (x:int) (y:int) = x*x + y*y;; val sumsq : int -> int -> int = <fun>

ocaml里的类型检查和判断是自动完成的


三、布尔型true和false

1. not方法:

# not (5=10);;- : bool = true

2. 条件表达式 if xx then xx else xx:

# if true then (3*5) else (5-2);;- : int = 15


三、浮点数float

浮点方法:

# 1. +. 2.1;;- : float = 3.1
# 2.3 *. -3.5;;- : float = -8.04999999999999893(*注意比较“+.”和“+”*)

需要注意的是,形如 1 + 1.0 或是 1 +. 1.0之类的运算都是会报错的,这时候需要用到类型转换函数type_of_type:

# 1 + 1.0;;Error: This expression has type float but an expression was expected of type         int# 1 +. 1.0;;Error: This expression has type int but an expression was expected of type         float# float_of_int 1 +. 1.0;;- : float = 2.



总结下(3月24日):

ocaml最基础的数据类型有如下几种(来源)

  1. int  在32位处理器上是31位的,64位处理器上是63位的,剩下的一位做了回收机制的flag。不过要是非想要c的效果,可以使用ocaml在Nativeint模块中提供的nativeint类型。同样的,uint也可以使用nativeint模仿
  2. bool true,false
  3. char 8位的字符,不支持utf-8和unicode
  4. string "Hello world"
  5. float ieee标准的双精度浮点数,不支持单精度浮点数
  6. unit 这个是很有意思的一个数据类型,写作(),用于制作序列运算,具体可以参照tpl书上的做法

ocaml基础的操作符:

  1. + 整型加法
  2. 整型减法
  3. ~-或-   整型负
  4. * 整型乘法
  5. /  整型除法,若除零则会raise一个Division_by_zero
  6. mod  整型同余,若第二个参数为0则会raise一个Division_by_zero
  7. land  整型的逐位逻辑与
  8. lor  整型的逐位或
  9. lxor  整型的逐位异或
  10. lsl  整型的逻辑左移
  11. lsr  整型的逻辑右移
  12. asr  整型的算数右移
  13. +.  浮点加法
  14. -.  浮点减法
  15. ~-.或-.  浮点负
  16. *.  浮点乘法
  17. /.  浮点除法
  18. **  浮点乘方
  19. @  列表连结
  20. ^  字符串连结
  21. !  取引用
  22. :=  引用赋址
  23. =  结构意义上的相等
  24. <>  结构意义上的不相等
  25. ==  物理意义上的相等
  26. !=  物理意义上的不相等
  27. <  小于
  28. <=  不大于
  29. >  大于
  30. >=  不小于
  31. &&  布尔与
  32. ||  布尔或

其中比较有意思的一个是结构意义上的相等和物理意义上的相等的区别。官方文档里给出了这样两段话:

e1 = e2 tests for structural equality of e1 and e2. Mutable structures (e.g. references and
arrays) are equal if and only if their current contents are structurally equal, even if the two
mutable objects are not the same physical object.
Equality between functional values raises
Invalid_argument. Equality between cyclic data structures may not terminate.

e1 == e2 tests for physical equality of e1 and e2. On mutable types such as references,
arrays, strings, records with mutable elds and objects with mutable instance variables, e1
== e2 is true if and only if physical modi cation of e1 also a ects e2. Onnon-mutable
types,
the behavior of ( == ) is implementation-dependent; however, it is guaranteed that
e1 == e2 implies compare e1 e2 = 0.


另外也要注意到,这些操作符在ocaml中也是被当作val对待的。联同其他的一些最常用的val一起被定义在Pervasives模块中,是ocaml默认包含的模块。

这个模块里常见的除了上面列举出来的,还有pred,succ,min,max,compare,raise,sin,abs,log,exp等等,篇幅所限就不写了。


四、递归函数

rec标识:

# let rec fact(n:int) = if n = 0 then 1 else n * fact(n-1);;val fact : int -> int = <fun>


五、列表

1. 元素类别必须相同:

# [1;2;3;];;- : int list = [1; 2; 3]
# [];;- : 'a list = []

2. 从前方追加元素,::读作"cons",是右结合的:

# 1::[2;3];;- : int list = [1; 2; 3]
# 1::2::3::[];;- : int list = [1; 2; 3]

3. 使用List模块中的List.hd和List.tl操纵列表元素:

# List.hd [1;2;3];;- : int = 1
# List.tl [1;2;3];;- : int list = [2; 3]

4. 一些例子:

1) 尾部追加元素

# let rec snoc(l:int list)(x:int)=  if l=[] then x::[]  else List.hd l :: snoc(List.tl l) x;;val snoc : int list -> int -> int list = <fun># snoc [5;4;3;2] 1;;- : int list = [5; 4; 3; 2; 1]

2) 倒置元素

# let rec revaux(l:int list)(res:int list)=  if l=[] then res  else revaux (List.tl l) (List.hd l :: res);;val revaux : int list -> int list -> int list = <fun># revaux [1;2;3][4;5;6];;- : int list = [3; 2; 1; 4; 5; 6]# let rev(l:int list) = revaux l [];;val rev : int list -> int list = <fun># rev [1;2;3;4;5];;- : int list = [5; 4; 3; 2; 1]

3) 重写递归为tail-recursive style

原递归:

# let rec fact(n:int)=  if n=0 then 1    else n*fact(n-1);;val fact : int -> int = <fun>

重写:

# let rec factaux(acc:int)(n:int)=  if n=0 then acc  else factaux(acc*n)(n-1);;val factaux : int -> int -> int = <fun># let fact(n:int)=factaux 1 n;;val fact : int -> int = <fun>

recursion style在返回后不需要进行计算


六、元组

1. 元素之间类型无限制:

# ("children",[3.1;2.5]);;- : string * float list = ("children", [3.1; 2.5])
# let cube (x:int) = x*x*x;;val cube : int -> int = <fun># (cube,"cube");;- : (int -> int) * string = (<fun>, "cube”)

2. 注意区分:

# let g(x,y) = x*y;;val g : int * int -> int = <fun>
# let g(x:int)(y:int) = x*y;;val g : int -> int -> int = <fun>


七、模式匹配

1. 基本形式match xx with xx a->b,若不能完整覆盖该类型则会报warning:

val fact : int -> int = <fun># let rec listSum(l:int list)=  match l with   []->0  | x::y-> x + listSum y;;val listSum : int list -> int = <fun>

2. 通配符 _:

# let rec fact(n:int)=  match n with  0->1    | _ -> n*fact(n-1);;val fact : int -> int = <fun>
# let lastName name=    match name with (n,_,_)->n;;val lastName : 'a * 'b * 'c -> 'a = <fun>


八、多态

‘a类型:

# let rec length l =   match l with  [] -> 0  | _::y -> 1 + length y;;val length : 'a list -> int = <fun>


九、异常

1. 定义一个exception,注意首字母大写:

# exception NegNum;;exception NegNum

2. raise使用异常:

# let rec fact n =  if n<0 then raise NegNum    else if n=0 then 1  else n*fact(n-1);;val fact : int -> int = <fun># fact (-3);;Exception: NegNum.


十、in

let … in e;;
等价为
# let … ;;# e;;

1. 本地函数

# let rec loop (n:int)=  if n=1 then 1    else n*loop(n-1) in   loop 10;;- : int = 3628800# loop 2;;Error: Unbound value loop

2.简单的split实现

# let split l =   let rec loop w l =    match l with       []->[w]      | (' '::ls) -> w::(loop [] ls)      | (c::ls) -> loop (w @ [c]) ls in    loop [] l;;val split : char list -> char list list = <fun>(*其中@操作是List.append的简写*)

3. split另一种实现

# let split l =  let rec loop w l=  match w,l with  _,[] -> [w]   | _,(' '::ls)->w::(loop [] ls)  | _,(c::ls)->loop (w@[c]) ls in  loop [] l;;val split : char list -> char list list = <fun>(*和例子2的效果完全相同,会在多个空格时产生空列表*)

4. 排除空列表的split实现

# let better_split l =  let rec loop w l =  match w,l with  [],[]->[]  | _,[]->[w]  | [],(' '::ls) -> loop [] ls     | _,(' '::ls) -> w::(loop [] ls)  | _,(c::ls) -> loop (w@[c]) ls in  loop [] l;;val better_split : char list -> char list list = <fun>


先写到这吧orz...


0 0