为啥 MergeSort 函数会发生值限制?

Posted

技术标签:

【中文标题】为啥 MergeSort 函数会发生值限制?【英文标题】:Why does value restriction happen with MergeSort function?为什么 MergeSort 函数会发生值限制? 【发布时间】:2012-09-22 04:11:19 【问题描述】:

我在 List 上有一个非常简单的 MergeSort 实现。

/// Divide the list into (almost) equal halves
let rec split = function
    | [] -> [], []
    | [x] -> [x], []
    | x1::x2::xs -> let xs1, xs2 = split xs
                    x1::xs1, x2::xs2

/// Merge two sorted lists
let rec merge xs ys =
    match xs, ys with
    | [], _ -> ys
    | _, [] -> xs
    | x::xs', y::ys' when x <= y -> x::merge xs' ys
    | _, y::ys' -> y::merge xs ys' 

let rec mergeSort = function
    | [] -> []
    | xs -> let xs1, xs2 = split xs
            merge (mergeSort xs1) (mergeSort xs2)

但每当我尝试使用 F# Interactive 中的任何输入进行测试时:

let xs = mergeSort [1;4;3;2];;

遇到值限制错误:

错误 FS0030:值限制。值“xs”已被推断为 有泛型类型 val xs : '_a list when '_a : comparison 将 'xs' 定义为一个简单的数据项,使其成为具有显式参数的函数,或者,如果 你不打算让它是通用的,添加一个类型注释。

为什么会这样?有什么简单的修复方法?

【问题讨论】:

见Finer Points of F# Value Restriction 当我将代码粘贴到 FSI 时,F# 2.0 Interactive build 2.0.0.0 上没有收到任何错误消息 @JohnPalmer:当然不是。尝试在某些输入上执行函数。 @PaoloFalabella:谢谢,我知道这篇文章。我只是不明白为什么会发生这种情况。 【参考方案1】:

您没有处理 mergeSort 中的 1 元素列表的特殊情况。 一般情况“太笼统”而无法推断出正确的类型。结果,编译器为函数推断出过于通用的类型('a list -> 'b list),结果始终是通用列表(由于值限制,这是不允许的)。

如果你这样修复它,类型将被正确推断为 'a list -> 'a list。

let rec mergeSort = function
    | [] -> []
    | [x] -> [x]
    | xs -> let xs1, xs2 = split xs
            merge (mergeSort xs1) (mergeSort xs2)

【讨论】:

这也解释了原始代码中奇数输入长度的崩溃

以上是关于为啥 MergeSort 函数会发生值限制?的主要内容,如果未能解决你的问题,请参考以下文章

为啥部分应用程序有值限制?

Python - 为啥通过值传递的 ndarray 在函数外部发生变化? [复制]

为啥聚合函数会限制记录

为啥在 MergeSort 中使用 InsertionSort 而不是 Merge 平均更快?

为啥 Collections.sort 使用 Mergesort 而 Arrays.sort 不使用?

为啥我的数组值会发生变化? [复制]