我试图更好地理解OCaml类型推断。我创建了这个例子:
let rec f t = match t with
| (l,r) -> (f l)+(f r)
| _ -> 1
我希望将它应用于任何具有嵌套对的二进制元组(对),以获得叶子的总数。示例:f((1,2),3)
函数f拒绝编译,因为(fl)类型中存在矛盾:"此表达式具有类型' a但表达式需要类型' a *' b"
问题:' a是任何类型,也不能是一对,或者由_ case处理?是否有任何方法可以将任意深度的元组转换为其他数据结构,例如变体?
PS:在C ++中,我会通过创建两个模板函数来解决这类问题,#34; f",一个用于处理元组和另一个类型。
答案 0 :(得分:5)
有一种方法可以做到这一点,但由于产生的复杂性,我不建议将它推荐给新用户。你应该习惯先写一些常规的OCaml。
也就是说,通过将必要的结构捕获为GADT,您可以以通用方式处理任意类型。对于这个简单的问题,这很容易:
type 'a ty =
| Pair : 'a ty * 'b ty -> ('a * 'b) ty
| Other : 'a ty
let rec count_leaves : type a . a -> a ty -> int =
fun a ty ->
match ty with
| Pair (ta, tb) -> count_leaves (fst a) ta + count_leaves (snd a) tb
| Other -> 1
注意a ty
上的模式匹配如何对应于(类型不佳)示例函数中值的模式匹配。
可以使用更完整的类型表示来编写更多有用的函数,尽管必须支持任意元组,记录,求和类型等,机器变得繁重和复杂。
答案 1 :(得分:3)
元组的任何组合都将具有完全由其类型描述的值形状(因为在类型结构中没有"选择")因此"叶子的数量和# 34;问题可以在编译时完全静态地回答。一旦你有一个在这种类型上运行的功能 - 这个功能被修复为仅对特定类型(和形状)进行操作。
如果你想构建一个可以有不同形状(但是相同类型 - 因此可以通过相同的函数处理)的树 - 你需要在混合中添加变体,即经典type 'a tree = Leaf of 'a | Node of 'a tree * 'a tree
或任何其他类型用一些动态的选择来描述价值"选择"形状。