OCaml交互式模式下let与val的关联关系及类型推导规则咨询
OCaml let绑定函数类型签名手动推导方法
OCaml的类型推导基于Hindley-Milner类型系统,不需要手动标注类型,编译器会自动推导得到最泛化的类型签名,手动推导可以遵循以下通用步骤:
- 先识别柯里化函数结构:
fun a -> fun b -> fun c -> ...的类型格式为类型a -> 类型b -> 类型c -> 最终返回值类型 - 给所有未知参数、返回值分配临时类型变量(比如用Tf代表f的类型,Tx代表x的类型)
- 根据函数体内的操作推导类型约束:
- 算术运算(如
+、-)要求操作数为int,返回值也为int - 函数调用
f x说明f必须是函数类型,且输入参数类型与x的类型完全匹配,即f的类型为Tx -> Tf返回值 - 嵌套调用
g (f x)说明g的输入参数类型等于f的返回值类型
- 算术运算(如
- 合并所有无冲突的类型约束,没有被具体类型约束的变量保留为泛型类型(即
'a、'b这类多态变量)
示例推导验证
示例1:let app = fun f -> fun x -> f (x);;
- 分配临时类型:f的类型为Tf,x的类型为Tx,返回值为Tret
- 函数体为
f x,推导约束:f必须是输入为Tx、返回为Tret的函数 →Tf = Tx -> Tret - 替换回柯里化类型结构:
Tf -> Tx -> Tret = (Tx -> Tret) -> Tx -> Tret,泛化后得到签名('a -> 'b) -> 'a -> 'b,与交互式环境输出一致。
示例2:let app = fun f -> fun x -> x (f+1);;
- 分配临时类型:f的类型为Tf,x的类型为Tx,返回值为Tret
- 推导约束:
f + 1要求f为int,运算结果为intx (f+1)说明x是输入为int、返回为Tret的函数 →Tx = int -> Tret
- 替换后得到签名:
int -> (int -> 'a) -> 'a,与输出一致。
示例3:let app = fun f -> fun x -> x (f);;
- 分配临时类型:f的类型为Tf,x的类型为Tx,返回值为Tret
- 推导约束:
x f说明x是输入为Tf、返回为Tret的函数 →Tx = Tf -> Tret - 泛化后得到签名:
'a -> ('a -> 'b) -> 'b,与输出一致。
示例4:let app2 = fun f -> fun g -> fun x -> g ( f x );;
- 分配临时类型:f的类型为Tf,g的类型为Tg,x的类型为Tx,返回值为Tret
- 推导约束:
f x说明Tf = Tx -> Tf_retg (f x)说明Tg = Tf_ret -> Tret
- 替换后得到签名:
('a -> 'b) -> ('b -> 'c) -> 'a -> 'c,与输出一致,这也是标准的函数组合子类型。
示例5:let app3 = fun f -> fun g -> fun x -> g f x+1 ;;
- 先处理优先级:OCaml中函数应用优先级高于算术运算符,因此
g f x+1等价于(g f x) + 1 - 推导约束:
+1要求g f x的返回值为intg f x说明g是双参数柯里化函数,第一个参数类型为f的类型Tf,第二个参数类型为x的类型Tx,返回值为int→Tg = Tf -> Tx -> int
- 替换后得到签名:
'a -> ('a -> 'b -> int) -> 'b -> int,与输出一致。
内容的提问来源于stack exchange,提问作者Besart Nuha
相关产品推荐
相关产品推荐

