ocaml快餐教程(2) - 定义变量与函数

上一节我们主要介绍了ocaml的基本数据类型。在这些基本数据类型的基础上,我们可以组成更复杂的数据结构,比如我们用逗号分隔一些类型的值,就构成了元组。

比如元组(1, 10.),就一个int * float类型的元组。

# (1,10.);;
- : int * float = (1, 10.)

再例如,由int64, int32, nativeint, int, float构成的元组:

# 1L, 1l, 1n, 1, 1. ;;
- : int64 * int32 * nativeint * int * float = (1L, 1l, 1n, 1, 1.)

我们再来个-1开会:

# Int64.minus_one, Int32.minus_one, Int.minus_one, Nativeint.minus_one ;;
- : int64 * int32 * int * nativeint = (-1L, -1l, -1, -1n)

变量绑定与模式匹配

我们可以通过let语句,将一个表达式绑定给一个变量,如:

# let a = 1,1l ;;
val a : int * int32 = (1, 1l)

针对于两个元素构成的元组,我们可以通过fst和snd函数来获取元素的值,例:

# let a = 1,1l ;;
val a : int * int32 = (1, 1l)
# let a1 = fst a;;
val a1 : int = 1
# let a2 = snd a;;
val a2 : int32 = 1l

超过两个元素的元组,没法使用fst和snd函数。但是我们可以在let左边也用变量元组去绑定元组的元素,这样的操作称为模式匹配。

# let a3,a4,a5 = 3, 4., 5n ;;
val a3 : int = 3
val a4 : float = 4.
val a5 : nativeint = 5n

我们也可以通过and的方式进行联合赋值:

# let a6 = 6n and a7 = 7l and a8 = 8. ;;
val a6 : nativeint = 6n
val a7 : int32 = 7l
val a8 : float = 8.

在模式匹配中,如果有的值不需要绑定变量,我们可以赋给"_",例:

# let a9, _ , a11 = 9e0, 10e-10, 11. ;;
val a9 : float = 9.
val a11 : float = 11.

10e-10的值就直接被pass掉了。

用let定义函数

如果绑定的值带有参数,那么就是定义了一个函数。
我们来看个例子:

# let s3 x = x * x * x ;;
val s3 : int -> int = <fun>
# s3 8 ;;
- : int = 512

这时候发现.区分开的好处了吧,类型容易被推导出来:

# let a x = x *. x ;;
val a : float -> float = <fun>

这时候ocaml面向对象的特性带来加成,有些不用系统,我们都推导的出来:

# let s_2 x = Float.abs x ;;
val s_2 : float -> float = <fun>
# s_2 1e8;;
- : float = 100000000.

用let定义的函数,也可以支持多个参数,比如我们定义一个算加法的函数:

# let add2 x y = x +. y ;;
val add2 : float -> float -> float = <fun>
# add2 100. 200. ;;
- : float = 300.

我们也可以用let来定义柯里化的函数。柯里化要求每次只能有一个参数,如果有多个参数,那么处理一个之后,返回值是另一个函数。
比如上面的add2需要x和y两个参数,我们给定一个值,比如说是2,那么就变成了一个专门加2的函数了:

# let add2_2 = add2 2. ;;
val add2_2 : float -> float = <fun>
# add2_2 100. ;;
- : float = 102.

function和fun

上面的定义方面没什么不好的,如果觉得跟前面讲的let绑定变量的方法不太一致,想要let f = <函数定义> 这种方式的话,可以使用function关键字来定义:

# let s2 = function x -> x *. x ;;
val s2 : float -> float = <fun>
# s2 1e-1 ;;
- : float = 0.0100000000000000019

function的好处是,它是柯里化的,只能支持一个参数。如果想要支持多个参数的话,我们可以嵌套。

我们来看个例子:

# let mul2 = function x -> (function y -> x *. y) ;;
val mul2 : float -> float -> float = <fun>
# mul2 1e8 1e-4 ;;
- : float = 10000.

另外,我们可以把参数变成元组,这样看起来可能比较像其它语言的函数:

# let div2 = function (x,y) -> x /. y ;;
val div2 : float * float -> float = <fun>

调用时需要给元组:

# div2 (1e8,-4.) ;;
- : float = -25000000.

最后,fun可以定义多参数的函数:

# let addx = fun x1 x2 x3 -> x1 + x2 +x3 ;;
val addx : int -> int -> int -> int = <fun>
# addx 1 2 3 ;;
- : int = 6

高阶函数

高阶函数,通俗地讲,就是不但值可以做为参数,函数也可以做为参数。

比如,我们想定义一个两个数的操作的函数,我们这样写:

# let higherf ops x y = ops x y ;;
val higherf : ('a -> 'b -> 'c) -> 'a -> 'b -> 'c = <fun>

这下我们就拥有泛型的能力了,比如针对整数加法,可以用Int.add做为ops,nativeint就用Nativeint.add,浮点数就用Float.add:

# higherf Int. add 1 2 ;;
- : int = 3
# higherf Nativeint.add 1n 2n ;;
- : nativeint = 3n
# higherf Float.add 1. 2. ;;
- : float = 3.

我们再举个例子,比如三角函数计算时都要求使用弧度,我们是不是可以将角度转弧度的过程能够应用于所有的三角函数呢?
我们可以这么写:

# let deg ops x = ops ( x *. Float.pi /. 180.) ;;
val deg : (float -> 'a) -> float -> 'a = <fun>

这样,我们再求角度的三角函数时,就可以通过deg sin, deg cos这样的方式去调用了:

# deg sin 90. ;;
- : float = 1.
# deg sin 45. ;;
- : float = 0.707106781186547462
# deg cos 180. ;;
- : float = -1.
# deg tan 90. ;;
- : float = 16331239353195370.
# deg tan 45. ;;
- : float = 0.999999999999999889

小结

小结下,我们可以用let来绑定变量,也可以来定义函数。可以直接定义函数,也可以通过function和fun来定义。推荐使用function,这样会柯里化。
函数可以给定部分参数,变成新的函数。
函数的参数也可以是函数,这样的函数叫做高阶函数。

ocaml快餐教程(2) - 定义变量与函数相关推荐

  1. ocaml快餐教程(3) - 基本结构

    ocaml快餐教程(3) - 基本结构 分支结构 ocaml中支持用if-then-else表达式. 例: # let pass x = if x>=60 then "pass&quo ...

  2. ocaml快餐教程(1) - 强类型语言

    ocaml快餐教程(1) - 强类型语言 Keep说:自律给我自由. 在汽车.航天.铁路等高可靠性要求的代码中,经常要求使用MISRA C/C++标准,该标准对于C语言中不同整数类型之间的赋值有比较严 ...

  3. mysql 触发器定义变量_MySQL 函数存储过程触发器定义简单示例

    1.变量提示 NEW 是新值-- OLD 是旧值 INSERT 只有NEW ----UPDATE有NEW和OLD ---DELETE只有OLD 2.准备测试表(userinfo.userinfolog ...

  4. python声明变量教程_Python定义变量

    变量就像是一个用来装东西的盒子,我们把要存储的东西放在这个盒子里面,再给这个盒子起一个名字.当我们需要用到盒子里的东西的时候,只要说出这个盒子的名字,就可以找到其中的东西了. 盒子里的东西是可以变化的 ...

  5. linux文件的定义变量的值,linux shell 自定义函数方法(定义、返回值、变量作用域)...

    一.定义shell函数(define function) 语法: [ function ] funname [()] { action; [return int;] } 说明: 1.可以带functi ...

  6. JS中定义式函数与变量时函数的差别

    2019独角兽企业重金招聘Python工程师标准>>> 在JS中代码的执行并不是一句一句的执行的,而是一段一段执行的,JS执行过程中,会把定义式函数语句提到最前面. //变量时函数 ...

  7. 变量和函数的定义和声明

    2. 定义和声明 2.1. extern和static关键字 在上一节我们把两个程序文件放在一起编译链接,main.c用到的函数push.pop和is_empty由stack.c提供,其实有一点小问题 ...

  8. Javascript中函数中定义变量无var

    参考: https://wiki.jikexueyuan.com/project/brief-talk-js/about-var.html 前段时间回答了一个关于定义变量时使用关键字 var 与否的区 ...

  9. Scala基础:定义变量和逻辑判断语句以及方法和函数

    定义变量和逻辑判断语句 package com.zy.scalaimport scala.collection.immutableobject ScalaDemo {def main(args: Ar ...

最新文章

  1. 011:视图函数介绍
  2. 11个优秀的Android开发开源项目
  3. Aliyun 挂载硬盘
  4. C#.Net 如何动态加载与卸载程序集(.dll或者.exe)6-----在不卸载程序域的前提下替换程序集文件。...
  5. POJ 2594 Treasure Exploration (可相交最小路径覆盖)
  6. umi搭建react+antd项目(一)环境配置
  7. nginx配置多个server
  8. 运行报错error: (-215:Assertion failed) !ssize.empty() in function 'cv::resize'
  9. 4 Convex optimization problems
  10. windows 如何在Windows命令行下配置IP地址
  11. Python的基础--对象 转
  12. 揭秘2018图灵奖评选:Jeff Dean李开复和Lecun写信推荐Hinton
  13. 谨记这10条,就能给别人留下好印象?
  14. 黄山归来不看岳:《Java开发手册(黄山版)》新增 11 条规约
  15. 电脑需要u盘启动的解决办法--蓝屏修复
  16. 2019春第四次课程设计实验报告
  17. DXF解析成运动控制程序
  18. 葫芦娃手游服务器未响应,葫芦娃手游闪退解决方法_葫芦娃手游闪退原因_玩游戏网...
  19. 记录手机app的使用时长
  20. PS实用小技巧--修改图片上的文字

热门文章

  1. 跨域window.opener
  2. 修正牛顿法matlab,牛顿算法及其改进【阻尼牛顿法、修正牛顿法】
  3. 前端实现简易吃豆人小游戏
  4. LoRaWAN MAC层数据包格式
  5. 浏览器被篡改修复方法
  6. Python爬虫: 用urllib2+beautifulsoup写的抓取网页内容的示例
  7. VCS入门教程(一)
  8. dpdk-20.11 rpm包编译
  9. python模板公式代码替换,Python - 字符串模板的安全替换(safe_substitute) 详解
  10. 随机看妹子_这是不可能的