1

我在模块范围上的 let 绑定上遇到 VR 错误,说它的一个参数是通用的,但我不知道为什么该参数首先是通用的。这是代码:

let private asJsonResponse (responseSource: _ Task) =
    fun (next: HttpFunc) (ctx: HttpContext) ->
        task {
            let! consumption = responseSource
            return! json consumption next ctx
        }

let getVal = someFuncThatReturnsTaskOfMyType() |> asJsonResponse

错误在最后一行:

错误 FS0030:值限制。 当将参数设为显式时,该值getVal已被推断为具有泛型类型 val getVal: (HttpFunc -> '_a -> Task<HttpContext option>),或者,如果您不打算使其成为泛型,请添加类型注释。'_a :> HttpContextgetVal

我知道它基本上可以概括ctx: HttpContext可以转换为HttpContext. 为什么会这样?为什么只针对这个参数而不是next: HttpFunc

HttpContext是一个类并且HttpFunc是一个函数类型,这是问题吗?

4

1 回答 1

0

如果您添加类型注释,它就会编译:

let getVal: HttpFunc -> HttpContext -> Task<HttpContext option> =
    someFuncThatReturnsTaskOfMyType() |> asJsonResponse

或添加显式参数:

let getVal f = asJsonResponse (someFuncThatReturnsTaskOfMyType()) f

简单的答案是 F# 编译器的类型推断机制并不完美。你可以在这里阅读:

F# 编译器会尝试猜测可能适合的最通用类型,但在某些情况下,编译器会觉得代码模棱两可,而且即使看起来它猜对了类型,它也需要您更具体

更具体的细节,这里是文档:

MSDN Automatic Generalization in F#有一些例子

通常,当您希望构造是泛型的但编译器没有足够的信息来概括它时,或者当您无意中在非泛型构造中省略了足够的类型信息时,就会发生值限制错误。

于 2020-12-25T19:33:59.460 回答