- 论坛徽章:
- 7
|
goingstudy 发表于 2013-12-10 09:24 ![]()
初学ocaml,请教点问题
1. let rec rev accum = function
2. h :: t -> rev (h :: accum) t
3. | [] -> accum
4. let rec rev_map f accum = function
5. h :: t -> rev_map f ( f h :: accum) t
6. | [] -> accum
7. let map f l = rev [] (rev_map f [] l)
复制代码
这是一个对list 进行map操作的尾递归,版主能给讲讲吗,看了老长时间没看懂。
还有就是, 函数的参数是可以省略吗, 如上面的rev , 用let 写的时候有一个参数,下面递归调用时有两个参数
希望版主能介绍点经验
我就多管闲事一次吧。
其实你如果真正理解什么是函数式编程的话,上面的代码很容易理解。首先回答你的第二个问题,本质上函数是编程里的函数你可以认为它们都只接收一个参数,只不过这个接收一个参数的函数可以返回另一个接收一个参数的函数,从而看上去好像可以接受多个参数,不管实现上是怎样的,你都可以认为多参数形式的函数定义只不过是单参数形式函数定义的一种语法糖。接着,要真正让你理解你提的第二个问题,你还得(真正意义上)懂匿名函数。我这里都提到了匿名函数,你肯定已经知道匿名函数就是没有名字的函数,刚才说了,函数式编程里一个函数可以返回另一个函数,事实上我们这里定义的 rev 以及 rev_map 都是(在形式上)定义为(分别)接收一个(两个)参数,并返回一个接收一个参数的(匿名)函数(这由右边的function来定义,参数个数可以从 function 和 -> 之间的参数个数数出来),这等同于 rev (rev_map) 是一个接收两个(三个)参数并返回一个非函数值的函数(当然也等同于一个接收0个(一个)参数并返回接收两个参数的函数),所以在let里虽然是只写了一个参数,但是,事实上调用的时候可以(而且一般会)使用两个参数(除非你想返回一个函数,而不是值),也就是- let rec rev accum = function
- h :: t -> rev (h :: accum) t
- | [] -> accum
复制代码 等同于- let rec rev accum list = match list with
- h :: t -> rev (h :: accum) t
- | [] -> accum
复制代码 (我对Haskell更熟一点,不过前几天刚看了一两段Ocaml代码,希望上面的改写没有任何问题)
回到你的第一个问题,为了方便叙述,我在上面的引用中给代码加了编号(后面称行,不过我有意没有给空行编号),第一行的意思是定义一个递归函数,rev,它接收一个参数 accum 并返回一个匿名函数,第二行的意思,这个匿名函数接收一个参数,但是,如果这个参数是一个非空列表的话,就把这个列表的首元素和h绑定,剩余的(是一个可能为空的列表)部分和t绑定,然后把 h 加到 accum 这个列表之前,并作为第一个参数,然后把t作为第二个参数递归调用rev,第三行的意思是如果匿名函数的参数是一个空列表的话就直接返回accum,所以这三行定义的rev函数的最终意思是它接收一个列表accum,和另一个列表(暂叫做xs),它把xs倒置过来,并加到accum前面,所以如果 accum 是[1,2,3], xs 是 [4,5,6],那么 rev accum xs 的结果就是[6,5,4,1,2,3]。第4,5,6行跟第1,2,3行意思差不多,只是rev_map还接收一个参数f,然后f本身是一个函数(是的,在函数式编程里把一个函数作为另一个函数的函数或者返回值都很普遍),然后递归的时候话把f作用到h上。最后一行就是这两个函数的应用,我就不详讲了。
要理解函数代码的关键是要(真正)理解函数式编程的基本概念。 |
|