ocaml快餐教程(2) - 定义变量与函数
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) - 定义变量与函数相关推荐
- ocaml快餐教程(3) - 基本结构
ocaml快餐教程(3) - 基本结构 分支结构 ocaml中支持用if-then-else表达式. 例: # let pass x = if x>=60 then "pass&quo ...
- ocaml快餐教程(1) - 强类型语言
ocaml快餐教程(1) - 强类型语言 Keep说:自律给我自由. 在汽车.航天.铁路等高可靠性要求的代码中,经常要求使用MISRA C/C++标准,该标准对于C语言中不同整数类型之间的赋值有比较严 ...
- mysql 触发器定义变量_MySQL 函数存储过程触发器定义简单示例
1.变量提示 NEW 是新值-- OLD 是旧值 INSERT 只有NEW ----UPDATE有NEW和OLD ---DELETE只有OLD 2.准备测试表(userinfo.userinfolog ...
- python声明变量教程_Python定义变量
变量就像是一个用来装东西的盒子,我们把要存储的东西放在这个盒子里面,再给这个盒子起一个名字.当我们需要用到盒子里的东西的时候,只要说出这个盒子的名字,就可以找到其中的东西了. 盒子里的东西是可以变化的 ...
- linux文件的定义变量的值,linux shell 自定义函数方法(定义、返回值、变量作用域)...
一.定义shell函数(define function) 语法: [ function ] funname [()] { action; [return int;] } 说明: 1.可以带functi ...
- JS中定义式函数与变量时函数的差别
2019独角兽企业重金招聘Python工程师标准>>> 在JS中代码的执行并不是一句一句的执行的,而是一段一段执行的,JS执行过程中,会把定义式函数语句提到最前面. //变量时函数 ...
- 变量和函数的定义和声明
2. 定义和声明 2.1. extern和static关键字 在上一节我们把两个程序文件放在一起编译链接,main.c用到的函数push.pop和is_empty由stack.c提供,其实有一点小问题 ...
- Javascript中函数中定义变量无var
参考: https://wiki.jikexueyuan.com/project/brief-talk-js/about-var.html 前段时间回答了一个关于定义变量时使用关键字 var 与否的区 ...
- Scala基础:定义变量和逻辑判断语句以及方法和函数
定义变量和逻辑判断语句 package com.zy.scalaimport scala.collection.immutableobject ScalaDemo {def main(args: Ar ...
最新文章
- 011:视图函数介绍
- 11个优秀的Android开发开源项目
- Aliyun 挂载硬盘
- C#.Net 如何动态加载与卸载程序集(.dll或者.exe)6-----在不卸载程序域的前提下替换程序集文件。...
- POJ 2594 Treasure Exploration (可相交最小路径覆盖)
- umi搭建react+antd项目(一)环境配置
- nginx配置多个server
- 运行报错error: (-215:Assertion failed) !ssize.empty() in function 'cv::resize'
- 4 Convex optimization problems
- windows 如何在Windows命令行下配置IP地址
- Python的基础--对象 转
- 揭秘2018图灵奖评选:Jeff Dean李开复和Lecun写信推荐Hinton
- 谨记这10条,就能给别人留下好印象?
- 黄山归来不看岳:《Java开发手册(黄山版)》新增 11 条规约
- 电脑需要u盘启动的解决办法--蓝屏修复
- 2019春第四次课程设计实验报告
- DXF解析成运动控制程序
- 葫芦娃手游服务器未响应,葫芦娃手游闪退解决方法_葫芦娃手游闪退原因_玩游戏网...
- 记录手机app的使用时长
- PS实用小技巧--修改图片上的文字