博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OCaml入门(5)
阅读量:5901 次
发布时间:2019-06-19

本文共 3620 字,大约阅读时间需要 12 分钟。

匿名函数

函数式语言中,函数是一等公民,它应该可以像其它类型(int,float,string等)一样,能支持“字面量”,这就是匿名函数。

utop # (fun x -> x + 1);;- : int -> int = 
utop # (fun x -> x + 1) 7;;- : int = 8

可以看到,匿名函数可以代替函数的位置来使用。

有些函数需要的参数是另一个函数,当然也可以用匿名函数传入。比如:

utop # List.map ~f:(fun x->x+1) [1;2;3];;- : int list = [2; 3; 4]

不要太在意: ~f: 这样的语法,这只是具名函数调用的用法。大多数语言中,函数的调用都是按位置来匹配参数的。

这样做的缺点是容易忘记哪个参数在哪个位置。Ocaml当然也支持按位置传参调用函数的方式,但同时鼓励按名字传参来调用函数,这样的程序更具可读性。

(你可能会觉得这多别扭啊,暂且忍受,人们往往都是习惯的奴隶)

匿名函数当然能绑定到一个符号,这样就成了具名函数:

utop # let plusone = fun x -> x + 1;;val plusone : int -> int = 
utop # plusone 5;;- : int = 6

这种定义如此普遍,Ocaml提供了语法糖来简化:

utop # let plusone x = x + 1;;val plusone : int -> int = 

这与上一个定义是完全一样的,只是语法偷懒了而已。

匿名函数也可以有多个参数:

utop # let diff x y = abs (x - y);;val diff : int -> int -> int = 
utop # diff 5 8;;- : int = 3

你可能会很奇怪这个函数的类型签名: int -> int -> int

在我们的想象中,应该是:(int, int)-> int 才更合理啊。

这正是函数式语言更数学化的特征之一。在数学上,严格地说,每个函数都只能传入一个参数,并且返回一个参数。

如果有一个函数看起来传入两个参数,它只不过是传入一个参数又返回了另一个函数的函数。

也就是说,本质上,上边的函数定义等价于:

utop # let diff = fun x -> (fun y -> abs (x - y));;val diff : int -> int -> int = 

这是个脑力体操,仔细想想吧。

函数式语言的威力恰在于:函数可以作为参数,函数可以作为返回值。

按照这个思路,我们顺理成章地可以这样写:

utop # let diff3 = diff 3;;val diff3 : int -> int = 
utop # diff3 8;;- : int = 5

对于多参的函数,只提供部分参数的做法很普遍,数学上叫做:偏参函数。

函数的递归

函数式语言不鼓励(甚至是不允许)使用变量 + 循环的编程模式,比起循环来,它更青睐于“递归”。

递归就是一函数直接或间接地调用自己。

utop # let rec len lst = match lst with| [] -> 0| h::tail -> 1 + len tail;; val len : 'a list -> int = 
utop # len [1;2;3;4];;- : int = 4 utop # len [];;- : int = 0

如果一函数是递归的,Ocaml要求必须明确地用 rec来修饰。

rec是recursive的缩写。

如果间接递归就需要一次把多个函数都定义出来,比如: is_even 来判断是否为偶数。这里只是为了示范概念,当然仅仅为这个小功能没必要这样大费周章。

utop # let rec is_even x =if x=0 then true else is_odd (x-1)and is_odd x =if x=0 then false else is_even (x-1);;val is_even : int -> bool = 
val is_odd : int -> bool =
utop # is_even 7;;- : bool = false utop # is_even 8;;- : bool = true

前缀与中缀

一般的函数调用都是前缀格式: 函数 参数 参数 ...

有的时候,两个参数时,中缀更符合习惯。比如: 1 + 2,   5 mod 3

Ocaml中,函数与运算符实在同样的东西,都是: function

中缀运算符如果加上括号,就回到了前缀的风格:

utop # (+) 5 8;;- : int = 13 utop # (mod) 10 3;;- : int = 1  utop # List.map ~f:((+) 3) [1;2;3;4];;- : int list = [4; 5; 6; 7]

自己定义中缀运算符也可以,必须从如下符号集合中组合:

! $ % & * + - . / : < = > ? @ ^ | ~ 比如:
utop # let (+!) (x1,y1) (x2,y2) = x1+x2, y1+y2;;val ( +! ) : int * int -> int * int -> int * int = 
utop # (1,2) +! (10,20);;- : int * int = (11, 22)

使用含有 * 的运算符需要格外小心,因为 (* 。。。。 *) 表示注释语句。

utop # ( * ) 3 5;;- : int = 15

这里括号与星号之间的空格是必须的!

Function

let ff x = match x with ... | ... | ...

这种模式如此普遍,OCaml提供了进一步的简化语法:

utop # let len = function| [] -> 0| h::t -> 1 + len t;;val len : 'a list -> int = 
utop # len [1;2];;- : int = 2

标签参数

多参数函数可以使用标签参数来增加可读性和灵活性。

下面的函数求坡度。

utop # let po ~path ~height = let pi = atan 1.0 *. 4. in(asin (height /. path)) *. 180.0 /. pi;;val po : path:float -> height:float -> float = 
utop # po ~path:10. ~height:1.;;- : float = 5.73917047727

既然参数有名字,顺序就无关紧要了。

utop # po ~height:1. ~path:10.;;- : float = 5.73917047727

 可选参数

可选参数就是可能出现,也可能省略的参数。在OCaml类型中表现为Option类型。

utop # let concat ?sep x y = let s = match sep with None->"" | Some x -> x inx ^ s ^ y;;val concat : ?sep:string -> string -> string -> string = 
utop # concat "dog" "cat";;- : string = "dogcat" utop # concat "dog" "cat" ~sep:",";;- : string = "dog,cat"

对于Option类型的解构太常用了,所以Ocaml进一步提供了简便语法:

utop # let concat ?(sep="") x y = x ^ sep ^ y;;val concat : ?sep:string -> string -> string -> string = 

含义与前边的定义完全相同。

 

转载于:https://www.cnblogs.com/gyhang/p/4785193.html

你可能感兴趣的文章
access中设置不等于
查看>>
hdu 1221 Rectangle and Circle
查看>>
Android 四大组件之四(ContentProvider)
查看>>
Android 四大组件之一(Activity)
查看>>
扫描(一)
查看>>
PIE SDK矢量数据的读取
查看>>
两种方式分别改变alertdialog的宽和高
查看>>
TextView-setCompondDrawables用法
查看>>
Centos7安装rabbitmq server 3.6.0
查看>>
iostat命令学习
查看>>
SQL 三种分页方式
查看>>
查看linux是ubuntu还是centos
查看>>
html video的url更新,自动清缓存
查看>>
IOS Xib使用——为控制器添加Xib文件
查看>>
CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙步骤
查看>>
【11】ajax请求后台接口数据与返回值处理js写法
查看>>
Python菜鸟之路:Jquery Ajax的使用
查看>>
LeetCode算法题-Maximum Depth of Binary Tree
查看>>
Cox 教学视频5
查看>>
Jenkins持续集成学习-搭建jenkins问题汇总
查看>>