字符串与数组索引的语法

gle*_*nsl 4 arrays string syntax ocaml

为什么数组和字符串索引使用微妙的不同语法?

例如

let _: int  = [|1;2;3|].(0)
let _: char = "123".[0]
Run Code Online (Sandbox Code Playgroud)

我(和其他人)发现这既奇怪又令人困惑.

oct*_*ron 8

出于与Ocaml +用于整数加法和+.浮点数添加的完全相同的原因:OCaml放弃ad-hoc多态/函数重载和索引运算符当前被认为是OCaml中的一种函数形式,因此受到与函数相同的限制.

更准确地说,索引运营商目前正在一个很浅的语法糖:解析器重写x.(n)Array.get x nx.(n) <- yArray.set x n y(或Array.unsafe_getArray.unsafe_set在编译时-unsafe的选项).同样, s.[n]被重写String.get s ns.[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)
Run Code Online (Sandbox Code Playgroud)

请注意,无法保证这种hackish代码将来会起作用.如果要定义自己的索引操作符,就可以开始OCaml的≥4.06由点之间插入至少一个(运营商)字符定义扩展索引操作符.和左括号(或者(,[,{).

let (.?()) dict key = Dict.find_opt dict key 
Run Code Online (Sandbox Code Playgroud)

如果你以某种方式希望减少索引操作符,那么就有一个命题可以使类似数组的数据类型的索引成为基本操作,而不是函数调用.这将允许使用类型导向的消歧,就像它已经为记录字段所做的那样.这意味着两者

 let first (s:string) = s.(0)
 let first (a: _ array) = a.(0)
Run Code Online (Sandbox Code Playgroud)

因为类型检查器将使用类型信息来解析应该使用哪个基元操作,所以是可能的.

但是,此提议仍在进行中(请参阅https://github.com/ocaml/ocaml/pull/616),因此现在需要通过语法区分字符串和通用数组索引.