练习
大多数练习的解决方案都可以获得。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 = 1fib 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 1add 5(add 5) 1add (5 1)
Exercise: average [★★]
定义一个中缀运算符 +/. 来计算两个浮点数的平均值。例如,
1.0 +/. 2.0 = 1.50. +/. 0. = 0.
Exercise: hello world [★]
在 utop 中键入以下内容:
- print_endline "Hello world!";;
- print_string "Hello world!";;
注意每个输出之间的差异。