对于列表,您可以进行模式匹配并迭代直到第n个元素,但对于元组,您将如何获取第n个元素?
答案 0 :(得分:11)
您可以通过解包 t -uple来获取 n -th元素,并使用价值解构,let
构造,match
构造或函数定义:
let ivuple = (5, 2, 1, 1)
let squared_sum_let =
let (a,b,c,d) = ivuple in
a*a + b*b + c*c + d*d
let squared_sum_match =
match ivuple with (a,b,c,d) -> a*a + b*b + c*c + d*d
let squared_sum_fun (a,b,c,d) =
a*a + b*b + c*c + d*d
match
- 构造在这里没有优于let
- 构造的优点,只是为了完整性而包含它。
只有少数情况下使用 t -uples来表示类型是正确的。大多数情况下,我们选择 t -uple,因为我们懒得定义类型,我们应该解释访问 n -th字段的问题em> t -uple或迭代 t -uple的字段作为一个严重的信号是时候切换到正确的类型。
t -uples有两个自然替代品:记录和数组。
我们可以看到记录为 t -uple,其条目被标记,因此,如果我们想要它们,它们绝对是 t -uples的最自然的替代品直接访问它们。
type ivuple = {
a: int;
b: int;
c: int;
d: int;
}
然后,我们通过撰写a
直接访问x
类型值ivuple
的字段x.a
。请注意,记录很容易通过修改进行复制,如let y = { x with d = 0 }
中所述。没有自然的方法来迭代记录的字段,主要是因为记录不需要是同质的。
大型²同构值集合由数组充分表示,允许直接访问,迭代和折叠。可能不方便的是,数组的大小不是其类型的一部分,但对于固定大小的数组,通过引入私有类型(甚至是抽象类型)可以很容易地避免这种情况。我在my answer中描述了一个关于“OCaml编译器检查向量长度”问题的技术示例。
在 t -uples中使用浮点数时,在仅包含浮点数的记录中和数组中,这些都是未装箱的。因此,在数值计算中从一种类型更改为另一种类型时,我们不应注意任何性能修改。
¹请参阅 TeXbook 。 ²大于4开始。
答案 1 :(得分:8)
由于OCaml元组的长度是类型的一部分,因此在编译时已知(并且已修复),因此您可以通过元组上的直接模式匹配来获得第n个项目。出于同样的原因,提取"任意长度元组的第n个元素的问题" 不能在实践中发生 - 这样的"元组"不能在OCaml的类型系统中表达。
每次需要投射元组时,您可能仍然不想写出模式,没有什么可以阻止您生成函数get_1_1
... get_i_j
...提取{ {1}} - 来自i
- 元组的元素,代码中出现j
和i
的任何可能组合,例如
j
不一定漂亮,但可能。
注意:之前我曾声称OCaml元组的长度最多为255,您可以简单地一劳永逸地生成所有可能的元组投影。正如@Virgile在评论中指出的那样,这是不正确的 - 元组可能是巨大的。这意味着预先生成所有可能的元组投影函数是不切实际的,因此在代码中出现限制" "上方。
答案 2 :(得分:2)
在OCaml中完全无异地编写这样的函数是不可能的。一种看待这种情况的方法是考虑函数的类型。有两个问题。首先,元组的每个大小都是不同的类型。因此,您无法编写访问不同大小元组元素的函数。第二个问题是元组的不同元素可以有不同的类型。列表没有这些问题,这就是为什么你可以List.nth
。
如果您愿意使用其元素类型相同的固定大小的元组,您可以编写@ user2361830所示的函数。
<强>更新强>
如果您确实拥有要通过索引访问的相同类型的值集合,则应该使用数组。
答案 3 :(得分:0)
这是一个函数,可将您需要执行的ocaml函数的字符串返回给您;)我经常使用它非常有帮助。
let tup len n =
if n>=0 && n<len then
let rec rep str nn = match nn<1 with
|true ->""
|_->str ^ (rep str (nn-1))in
let txt1 ="let t"^(string_of_int len)^"_"^(string_of_int n)^" tup = match tup with |" ^ (rep "_," n) ^ "a" and
txt2 =","^(rep "_," (len-n-2)) and
txt3 ="->a" in
if n = len-1 then
print_string (txt1^txt3)
else
print_string (txt1^txt2^"_"^txt3)
else raise (Failure "Error") ;;
例如:
tup 8 6;;
返回:
let t8_6 tup = match tup with |_,_,_,_,_,_,a,_->a
当然:
val t8_6 : 'a * 'b * 'c * 'd * 'e * 'f * 'g * 'h -> 'g = <fun>