为什么数组和字符串索引使用微妙的不同语法?
E.g。
let _: int = [|1;2;3|].(0)
let _: char = "123".[0]
我(和其他人)认为这既奇怪又令人困惑。
答案 0 :(得分:7)
出于完全相同的原因,Ocaml使用+
进行整数加法,+.
进行浮点数加法:OCaml放弃ad-hoc多态/函数重载和索引运算符当前被认为是一种函数形式因此,OCaml受到与功能相同的限制。
更准确地说,索引运算符目前是一个非常浅的语法糖:解析器将x.(n)
重写为Array.get x n
而x.(n) <- y
重写为Array.set x n y
(或Array.unsafe_get
并且如果使用Array.unsafe_set
选项进行编译,则-unsafe
。同样的,
s.[n]
被重写为String.get s n
,s.[n]<-x
变为String.set s n x
。
这意味着可以通过定义新的Array
模块来定义自己的索引运算符。例如,以下不明智的
技巧将使数组索引从1
开始:
module Array = struct
include Array
let get a n = get a (n-1)
let unsafe_get a n
end
;; [|1|].(1)
请注意,无法保证此类hackish代码将来可以使用。如果要定义自己的索引运算符,可以从OCaml≥4.06开始,通过在点.
和左括号({{1}之间插入至少一个(运算符)字符来定义扩展索引运算符},(
,[
)。
{
如果你以某种方式希望减少索引操作符,那么有一个建议是为类似数组的数据类型建立一个原始操作而不是函数调用。这将允许使用类型导向的消歧,就像它已经为记录字段所做的那样。这意味着两者
let (.?()) dict key = Dict.find_opt dict key
是可能的,因为类型检查器将使用类型信息来解析应该使用哪个基本操作。
但是,此提案仍在进行中(请参阅https://github.com/ocaml/ocaml/pull/616),因此现在需要通过语法区分字符串和通用数组索引。