F#:键入推断未找到正确的重载

时间:2013-06-28 09:14:25

标签: f# type-inference

我已经编写了一个函数并且我已经开始重构它,但是我遇到了一些问题,“方法'Round'的唯一重载无法根据此程序点之前的类型信息来确定。”错误,但我不明白为什么。

let CheckValuesLin (lowValue, highValue) multiplier (sigFigs:int) =
    let arithmean (lowValue, highValue) =
        (lowValue + highValue) / 2.0
    let createRangeValue numberModifier meanfunction= 
        let mean = meanfunction (lowValue, highValue)
        let rangeValue = mean + (numberModifier mean) * multiplier
        Math.Round(rangeValue, sigFigs)
    let createRangeValues valueCreatingFunction=
        (createRangeValue makeNegative arithmean, createRangeValue keepPositive arithmean)
    let greatestMinValue, lowestMaxValue = createRangeValues createRangeValue
    (greatestMinValue, lowestMaxValue)

失败的行是Math.Round行,当我将range设置为range: float时,它会消失。这让我感到困惑,因为我悬停的一切似乎已经推断出正确的类型,包括范围和均值。

我不介意把类型暗示,我只想知道它失败的原因。

1 个答案:

答案 0 :(得分:2)

问题是F#类型推断是严格从左到右,从上到下。

createRangeValue函数中,编译器只能推断所有值都是数值,没有什么可以强制类型为float

虽然稍后调用arithmean似乎会给某些值浮点类型,但这会在调用Round之后发生,因此编译器无法推断类型。

编辑更多细节: 基本上编译器会看到:

let lowValue = 0.0 //I am being genrous by making this have a type
let highValue = 0.0
let sigFigs = 0 //this type is known
let createRangeValue (numberModifier) (meanfunction) multiplier= 
    let mean = meanfunction (lowValue, highValue)    
    let rangeValue = mean + (numberModifier mean) * multiplier
    Math.Round(rangeValue, sigFigs)

在这种情况下,rangeValue可以是floatDecimal,因为两者都可以满足所有约束条件。

对我来说,这很好用

open System
let makeNegative a = -a
let keepPositive a = a
let CheckValuesLin (lowValue, highValue) multiplier (sigFigs:int) =
    let arithmean (lowValue, highValue) =
        (lowValue + highValue) / 2.0
    let createRangeValue numberModifier (meanfunction: float * float -> float)= 
        let mean = meanfunction (lowValue, highValue)
        let rangeValue = mean + (numberModifier mean) * multiplier
        Math.Round(rangeValue, sigFigs)
    let createRangeValues valueCreatingFunction=
        (createRangeValue makeNegative arithmean, createRangeValue keepPositive arithmean)
    let greatestMinValue, lowestMaxValue = createRangeValues createRangeValue
    (greatestMinValue, lowestMaxValue)