练习
大多数练习的解决方案都可以获得。2022 年秋季是这些解决方案的首次公开发布。尽管康奈尔大学的学生已经可以获得这些解决方案几年了,但更广泛的传播将揭示可以进行改进的地方是不可避免的。我们很乐意添加或更正解决方案。请通过 GitHub 进行贡献。
Exercise: values [★]
以下是每个 OCaml 表达式的类型和值是什么?
-
7 * (1 + 2 + 3)
-
"CS " ^ string_of_int 3110
提示:将每个表达式输入到顶层,它会告诉你答案。注意: ^
不是指数运算。
Exercise: operators [★★]
查看 OCaml 手册中所有运算符的表格(您需要向下滚动以在该页面上找到它)。
- 写一个表达式,将
42
乘以10
。 - 编写一个表达式,将
3.14
除以2.0
。提示:在 OCaml 中,整数和浮点运算符的写法不同 - 编写一个表达式,计算
4.2
的七次方。注意:OCaml 中没有内置的整数指数运算符(顺便说一句,在 C 语言中也没有),部分原因是大多数 CPU 不提供这种操作。
Exercise: equality [★]
- 编写一个表达式,使用结构相等性比较
42
和42
。 - 编写一个表达式,使用结构相等性比较 "
hi
" 和 "hi
" 。结果是什么? - 编写一个表达式,使用物理相等性比较 "
hi
" 和 "hi
" 。结果是什么?
Exercise: assert [★]
- 将
assert true;;
输入到 utop 中,看看会发生什么。 - 将
assert false;;
输入到 utop 中,看看会发生什么。 - 编写一个表达式,断言
2110
不等于3110
(在结构上)。
Exercise: if [★]
编写一个 if
表达式,如果 2
大于 1
,则评估为 42
,否则评估为
7` 。
Exercise: double fun [★]
利用上面的增量函数作为指导,定义一个函数 double
,它将其输入乘以 2
。例如, double 7
将是 14
。通过将其应用于一些输入来测试您的函数。将这些测试用例转换为断言。
Exercise: more fun [★★]
- 定义一个函数,计算浮点数的立方。通过将该函数应用于几个输入来测试它
- 定义一个函数,计算整数的符号(
1
、0
或-1
)。使用嵌套的if
表达式。通过将其应用于几个输入来测试您的函数。 - 定义一个函数,根据给定的半径计算圆的面积。使用
assert
测试您的函数
对于后者,请记住浮点运算并不精确。与其断言一个确切的值,你应该断言结果是“足够接近”,例如,误差在 1e-5
之内。如果这对你来说是陌生的,值得阅读关于浮点运算的相关内容。
一个接受多个输入的函数可以通过在 let
定义的一部分提供这些输入的附加名称来定义。例如,以下函数计算三个参数的平均值:
let avg3 x y z = (x +. y +. z) /. 3.
Exercise: RMS [★★]
定义一个函数,计算两个数字的均方根,即 \( \sqrt{\frac{x^2 + y^2}{2}} \)
。用 assert
测试您的函数。
Exercise: date fun [★★★]
定义一个函数,该函数接受一个整数 d
和一个字符串 m
作为输入,并在 d
和 m
形成有效日期时返回 true
。在这里,有效日期的月份必须是以下缩写之一:Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sept,Oct,Nov,Dec
。日期必须是介于 1
和该月最少天数之间的数字,包括边界值。例如,如果月份是 Jan,则日期介于 1
和 31
之间,包括边界值;如果月份是 Feb
,则日期介于 1
和 28
之间,包括边界值。
你的函数可以有多简洁(即代码行数少且短)?你肯定可以做到少于 12
行。
Exercise: fib [★★]
定义一个递归函数 fib : int -> int
,使得 fib n
是斐波那契数列中的第 n
个数字,该数列为 1, 1, 2, 3, 5, 8, 13, ...
即:
fib 1 = 1
,fib 2 = 1, and fib 2 = 1
fib n = fib (n-1) + fib (n-2) for any n > 2
.
在顶层测试您的函数。
Exercise: fib fast [★★★]
您的 fib 实现计算第 50 个斐波那契数的速度有多快?如果计算几乎是瞬间完成的,那么恭喜!但大多数人最初想到的递归解决方案似乎会无限期地挂起。问题在于明显的解决方案会重复计算子问题。例如,计算 fib 5
需要同时计算 fib 3
和 fib 4
,如果这些分开计算,实际上会重复大量工作(指数级别的工作量)。
创建一个函数 fib_fast
,只需要线性数量的工作。提示:编写一个递归辅助函数 h : int -> int -> int -> int
,其中 h n pp p
定义如下:
h 1 pp p = p
,h n pp p = h (n-1) p (pp+p)
对于任何n > 1
。
h
的概念是假设前两个斐波那契数是 pp
和 p
,然后计算向前 n
个数字。因此, fib n = h n 0 1
对于任何 n > 0
。
n
的第一个值是多少,使得 fib_fast n
为负,表明整数溢出发生了?
Exercise: poly types [★★★]
以下每个函数的类型是什么?您可以要求顶层检查您的答案。
let f x = if x then x else x
let g x y = if y then x else x
let h x y z = if x then y else z
let i x y z = if x then y else y
Exercise: divide [★★]
编写一个函数 divide : numerator:float -> denominator:float -> float
。应用您的函数。
练习:结合律 [★★]
设我们已经定义了 let add x y = x + y
。以下哪个会产生一个整数,哪个会产生一个函数,哪个会产生一个错误?做出答案,然后在 toplevel 中检查你的答案。
add 5 1
add 5
(add 5) 1
add (5 1)
Exercise: average [★★]
定义一个中缀运算符 +/.
来计算两个浮点数的平均值。例如,
1.0 +/. 2.0 = 1.5
0. +/. 0. = 0.
Exercise: hello world [★]
在 utop
中键入以下内容:
- print_endline "Hello world!";;
- print_string "Hello world!";;
注意每个输出之间的差异。